Nice programing

Java 사용자가 자주 예외를 조용히 사용하는 이유는 무엇입니까?

nicepro 2020. 10. 17. 12:22
반응형

Java 사용자가 자주 예외를 조용히 사용하는 이유는 무엇입니까?


전에는 심각한 Java 코딩을 한 적이 없었지만 기존 기술 (Delphi 및 C #)을 기반으로 구문, 라이브러리 및 개념을 배웠습니다. 내가 이해하기 힘든 한 가지는 다음 printStackTrace과 같이 예외를 조용히 소비하는 코드를 너무 많이 보았다는 것입니다 .

    public void process() {
        try {
            System.out.println("test");
        } catch(Exception e) {
            e.printStackTrace();
        }
    }

내가 만난 거의 모든 Java 기사 및 프로젝트에는 이와 유사한 코드가 있습니다. 내 지식에 따르면 이것은 매우 나쁩니다. 예외는 거의 항상 다음과 같이 외부 컨텍스트로 전달되어야합니다.

    public void process() {
        try {
            System.out.println("test");
        } catch(Exception e) {
            e.printStackTrace();
            throw new AssertionError(e);
        }
    }

대부분의 경우 예외는 기본 프레임 워크 (예 : Java Swing)에 속하는 가장 바깥 쪽 루프에서 처리됩니다. Java 세계에서 이와 같이 코딩하는 것이 표준으로 보이는 이유는 무엇입니까? 의아해합니다.

내 배경에 따라 printStackTrace를 완전히 제거하고 싶습니다 . 처리되지 않은 일명 RuntimeException(또는 더 나은 방법 AssertionError) 으로 간단히 다시 던진 다음 가장 적절한 위치 인 프레임 워크 가장 바깥 쪽 루프에서 포착하고 기록합니다.

    public void process() {
        try {
            System.out.println("test");
        } catch(Exception e) {
            throw new AssertionError(e);
        }
    }

나는 항상 다음 시나리오와 비슷하다고 생각했습니다.

"남자가 총에 맞습니다.

그는 숨을 참으며 버스를 타는 데 충분한 힘이 있습니다.

10 마일 후 그 남자는 버스에서 내리고 몇 블록을 걷다가 죽습니다. "

경찰이 시체에 도착하면 방금 일어난 일에 대한 단서가 없습니다. 결국 그럴 수도 있지만 훨씬 더 어렵습니다.

더 나은 것은 :

"한 남자가 총에 맞아 즉시 죽고 시체는 방금 일어난 살인 자리에 정확히 놓여 있습니다."

경찰이 도착하면 모든 증거가 제자리에 있습니다.

시스템이 실패하는 경우 빠른 실패 가 더 좋습니다.

질문에 답하기 :

  1. 무지.
      +
  2. 나태

편집하다:

물론 catch 섹션이 유용합니다.

예외를 가지고 무언가를 할 수 있다면, 그것이해야 할 곳입니다.

아마도 그것은 주어진 코드에 대한 예외가 아니라 아마도 예상되는 것 일 것입니다.

그리고 예, catch를 사용 하여 추상화에 적합한 예외던질 수 있습니다.


일반적으로 이는 예외 처리를 사용하여 try-catch 블록에 문제가되는 코드를 래핑하는 유용한 '빠른 수정'을 제공하는 IDE 때문입니다. 아이디어는 실제로 무언가를하지만 게으른 개발자는하지 않는다는 것입니다.

이것은 의심 할 여지없이 잘못된 형태입니다.


  1. Java는 모든 예외를 명시 적으로 처리하도록합니다. 코드에서 호출하는 메서드가 FooException 및 BarException을 throw하도록 선언 된 경우 코드는 해당 예외를 처리 (또는 throw) 해야 합니다. 이에 대한 유일한 예외 는 닌자처럼 침묵하는 RuntimeException 입니다.
  2. 많은 프로그래머가 게으르고 (자신을 포함하여) 스택 추적을 인쇄하는 것은 매우 쉽습니다.

이것은 고전적인 짚맨의 주장 이다. printStackTrace()디버깅 보조 도구입니다. 당신은 블로그 나 잡지에서 그것을 봤다면 작가가 포인트 설명에 더 많은 관심을했기 때문에 그것은이었다 다른 예외 처리보다 더합니다. 프로덕션 코드에서 본다면 해당 코드의 개발자는 무지하거나 게으른 것입니다. "자바 세계"에서 일반적인 관행의 예로 간주되어서는 안됩니다.


나는 이것이 종종 두 가지 이유가 있음을 알았습니다.

  1. 프로그래머는 게으르다
  2. 프로그래머는 해당 구성 요소에 대한 진입 점을 보호하기를 원했습니다 (올바르게 또는 잘못됨)

나는 이것이 자바에만 국한된 현상이라고 생각하지 않는다. C #과 VB.Net에서도 이러한 코딩을 자주 보았습니다.

표면적으로는 매우 충격적이고 끔찍해 보입니다. 그러나 실제로는 새로운 것이 아닙니다. 오류 코드 반환 값과 예외를 사용하는 C ++ 응용 프로그램에서 항상 발생합니다. 그러나 차이점은 잠재적으로 치명적인 반환 값을 무시하는 것이 void를 반환하는 함수를 호출하는 것과 실제로 다르지 않다는 것입니다.

Foo* pFoo = ...;
pFoo->SomeMethod(); // Void or swallowing errors, who knows?

이 코드는 더 좋아 보이지만 SomeMethod ()가 HResult를 반환한다고 말하면 의미 상 예외를 삼키는 것과 다르지 않습니다.


확인 된 예외 는 실패한 실험 이기 때문에

(아마 printStackTrace ()가 진짜 문제 입니까? :)


나는 이런 종류의 느슨한 오류 처리 동작이 Java 프로그래머에게 근본적인 것임을 암시하는 어조를 약간 원망한다고 말해야합니다. 물론 Java 프로그래머는 다른 모든 프로그래머와 마찬가지로 게으르고 Java는 인기있는 언어이므로 예외를 삼키는 많은 코드를 보게 될 것입니다.

또한 다른 곳에서 지적했듯이, 개인적으로는 문제가 없지만 Java의 검사 된 예외 선언에 대해 이해할 수있는 좌절감이 있습니다.

제 생각에 제가 문제가되는 것은 컨텍스트를 고려하지 않고 웹상의 많은 기사와 코드 조각을 훑어보고 있다는 것입니다. 사실, 특정 API의 작동 방식을 설명하거나 무언가를 시작하는 방법을 설명하려는 기술 기사를 작성할 때 코드의 일부 측면 (직접적이지 않은 오류 처리)을 건너 뛸 가능성이 매우 높습니다. 특히 예제 시나리오에서 예외가 발생할 가능성이없는 경우 시연중인 항목과 관련된 항목이 폐기 될 가능성이 높습니다.

People who write articles of that nature have to maintain a reasonable signal-to-noise ratio, and rather fairly, I think, that means they have to assume you know some basics about the language you're developing in; how to deal properly with errors, and a bunch of other things. If you come across an article and notice a lack of proper error checking, then that's fine; just make sure that when you incorporate those ideas (but of course, never the exact code itself, right?) into your production code, you'll deal with all those bits and bobs that the author sensibly left out, in a manner that's most suited to what you're developing.

나는 그런 문제로 돌아 가지 않고 쉽게 해결할 수있는 매우 높은 수준의 소개 기사에 문제가 있지만, 오류 처리와 관련하여 Java 프로그래머의 특별한 "마인드"가 없다는 점에 유의하십시오. 나는 모든 문제를 처리하는 데 신경 쓰지 않는 사랑하는 C # 프로그래머를 많이 알고 있습니다.


System.out print 또는 e.printStackTrace ()-System.out의 사용을 의미하는 것은 일반적으로 누군가가 부지런한 일을하지 않았 음을 의미하는 붉은 깃발입니다. 데스크톱 Java 애플리케이션을 제외하고 대부분의 Java 애플리케이션은 로깅을 사용하는 것이 좋습니다.

메소드의 실패 모드가 작동하지 않는 경우 이유 (및 존재)를 기록하든 안하든 예외를 먹는 것은 완벽합니다. 그러나 더 일반적으로 catch 절은 일종의 예외적 인 조치를 취해야합니다.

예외를 다시 던지는 것은 필요한 정보가 여전히 사용 가능한 수준에서 작업의 일부를 정리하기 위해 catch를 사용하거나 예외를 호출자에게 더 잘 맞는 예외 유형으로 변환해야 할 때 가장 잘 수행되는 작업입니다.


catch 블록이 실제로 비어있는 경우에만 자동으로 소비됩니다.

기사가 진행되는 한 예외를 처리하는 방법 외에 다른 점을 증명하는 데 더 흥미로울 것입니다. 그들은 단지 요점을 바로 잡고 가능한 가장 짧은 코드를 원합니다.

분명히 당신이 옳습니다. 예외가 '무시'될 경우 최소한 기록되어야합니다.


다른 사람들이 지적했듯이 이것이 보이는 이유는 다음 세 가지 이유 중 하나입니다.

  1. IDE가 try-catch 블록을 생성했습니다.
    • 코드를 복사하여 붙여 넣었습니다.
    • 개발자는 스택 추적을 디버그에 넣었지만 예외를 제대로 처리하기 위해 돌아 오지 않았습니다.

마지막 지점은 발생할 가능성이 가장 낮습니다. 나는 누군가가 정말로 이런 식으로 디버그한다고 생각하지 않기 때문에 이것을 말합니다. 디버거를 사용하여 코드를 단계별로 실행하는 것이 훨씬 더 쉽게 디버깅 할 수있는 방법입니다.

catch 블록에서 수행 해야하는 작업에 대한 가장 좋은 설명은 Joshua Bloch효과적인 Java 9 장에서 찾을 수 있습니다 .


C #에서는 모든 예외가 런타임 예외이지만 Java에서는 메서드에서 포착하거나 선언해야하는 런타임 예외 및 확인 된 예외가 있습니다. 끝에 "throws"가있는 메서드를 호출하는 경우 여기에 언급 된 예외를 포착하거나 메서드에서 해당 예외를 선언해야합니다.

Java 기사는 예외 처리가 기사의 주제와 관련이 없기 때문에 일반적으로 스택 추적을 인쇄하거나 주석이 있습니다. 하지만 프로젝트에서는 예외 유형에 따라 이에 대해 조치를 취해야합니다.


프로그래머가 자신의 일을 제대로한다면 이것을 자주 보게 될 것입니다. 예외를 무시하는 것은 나쁘고 나쁜 습관입니다! 그러나 일부 사람들이이를 수행하는 데에는 몇 가지 이유와 더 적절한 솔루션이 있습니다.

  • "이건 안될거야!" 물론, 언젠가는이 예외가 발생하지 않는다는 것을 "알고"있지만 런타임 예외를 다시 던지는 것이 더 적절합니다. 예외는 그냥 무시하는 대신 "원인"으로 간주됩니다. 나는 그것이 미래에 언젠가 점령 될 것이라고 장담한다. ;-)

  • 프로토 타이핑 코드 제대로 작동하는지 확인하기 위해 항목을 입력하는 경우 발생할 수있는 모든 예외를 무시할 수 있습니다. 이것은 내가 게으른 catch (Throwable)를하는 유일한 경우입니다. 그러나 코드가 유용한 것으로 밝혀지면 적절한 예외 처리를 포함합니다.

  • "어떻게 해야할지 모르겠어요!" 나는 많은 코드, 특히 라이브러리 코드를 보았는데, 이는 애플리케이션의이 계층에서는 적절한 처리를 수행 할 수 없기 때문에 발생하는 예외를 삼킨다. 이러지마! 메소드 서명에 throws 절을 추가하거나 예외를 라이브러리 특정 항목으로 래핑하여 예외를 다시 발생 시키십시오.


항상이를 전달하거나 실제 상황에서 적절하게 처리해야합니다. 많은 기사와 튜토리얼이 코드를 단순화하여 더 중요한 사항을 파악할 수 있으며 단순화하기 가장 쉬운 것 중 하나는 오류 처리입니다 (오류 처리에 대한 기사를 작성하는 것이 아니라면 :). 자바 코드가 예외 처리를 확인하므로 간단한 자동 (또는 로깅 문) catch 블록을 설정하는 것이 작업 예제를 제공하는 가장 간단한 방법입니다.

예제 코드가 아닌 다른 곳에서 이것을 찾으면 지금까지 너무 많은 예제가있을 수 있지만 코드를 TDWTF로 자유롭게 전달하십시오. :)


대부분의 자바 프로그래머는 예외로 무엇을해야할지 모르고 "명목상"사례의 코딩을 늦추는 성가심으로 간주합니다. 물론 완전히 틀렸지 만 예외를 올바르게 처리하는 것이 중요하다는 것을 설득하기는 어렵습니다. 그런 프로그래머를 만날 때마다 (빈번하게 발생) 그에게 두 가지 읽기 항목을 제공합니다.

  • 자바의 유명한 생각
  • Barry Ruzek의 짧고 흥미로운 기사는 여기에서 볼 수 있습니다. www.oracle.com/technology/pub/articles/dev2arch/2006/11/effective-exceptions.html

그건 그렇고, 나는 RuntimeException에 포함 된 예외를 다시 던지기 위해 유형이 지정된 예외를 포착하는 것이 어리 석다는 데 강력히 동의합니다.

  • 잡으면 처리하십시오.
  • 그렇지 않으면 메서드 서명을 변경하여 처리하거나 처리 할 수없는 가능한 예외를 추가하여 호출자가 스스로 처리 할 수있는 기회를 갖게됩니다.

확인 된 예외와 인터페이스의 조합으로 인해 코드가 결코 throw되지 않는 실행을 처리해야하는 상황이 발생합니다. (일반 상속에도 동일하게 적용되지만 인터페이스로 설명하는 것이 더 일반적이고 더 쉽습니다)

이유 : 인터페이스 구현은 인터페이스 사양에 정의 된 것 이외의 예외를 throw (확인) 할 수 없습니다. 이러한 이유로 인터페이스를 구현하는 클래스의 어떤 메서드가 실제로 예외를 throw해야할지 알지 못하는 인터페이스 작성자는 모든 메서드가 하나 이상의 예외 유형을 throw 할 수 있음을 지정할 수 있습니다. 예 : JDBC, 모든 것과 그 할머니가 SQLException을 던지도록 선언됩니다.

그러나 실제로 실제 구현의 많은 방법은 단순히 실패 할 수 없으므로 어떤 상황에서도 예외가 발생하지 않습니다. 이 메서드를 호출하는 코드는 여전히 예외를 "처리"해야하며 가장 쉬운 방법은 예외를 삼키는 것입니다. 아무도 실행되지 않는 쓸모없는 오류 처리로 코드를 복잡하게 만들고 싶지 않습니다.


지적했듯이 printStackTrace () 호출은 실제로 자동 처리가 아닙니다.

이런 종류의 예외를 "삼키는"이유는 예외를 체인 위로 계속 전달하는 경우에도 예외를 어딘가 에서 처리 하거나 응용 프로그램이 중단되도록해야하기 때문입니다. 따라서 정보 덤프와 함께 발생하는 수준에서 처리하는 것은 정보 덤프를 사용하여 최상위 수준에서 처리하는 것보다 나쁘지 않습니다.


Its lazy practice - nothing short of it really.

Its usually done when you really don't care about the exception - rather than increasing your finger-work.


I disagree that rethrowing a checked exception is a better idea. Catching means handling; if you have to rethrow, you shouldn't catch. I'd add the throws clause to the method signature in that case.

I would say that wrapping a checked exception in an unchecked one (e.g., the way Spring wraps the checked SQLException into an instance of its unchecked hierarchy) is acceptable.

Logging can be considered handling. If the example was changed to log the stack trace using log4j instead of writing to the console, would that make it acceptable? Not much of a change, IMO.

The real issue is what is considered exceptional and an acceptable recovery procedure. If you can't recover from the exception, the best you can do is report the failure.


Please don't ever, ever, ever wrap a checked exception in an unchecked exception.

If you find yourself dealing with exceptions that you don't think you should then my advice is that you are probably working at the wrong level of abstraction.

I'll elaborate: checked and unchecked exceptions are two very different beasts. Checked exceptions are similar to the old method of returning error codes... yes, they are somewhat more painful to handle than error codes but they have advantages too. Unchecked exceptions are programming errors and critical system failures... exceptional exceptions in other words. When trying to explain what an exception is a lot of people get into a complete mess because they don't acknowledge the difference in these two, very different, cases.


Because they haven't learned this trick yet:

class ExceptionUtils {
    public static RuntimeException cloak(Throwable t) {
        return ExceptionUtils.<RuntimeException>castAndRethrow(t);
    }

    @SuppressWarnings("unchecked")
    private static <X extends Throwable> X castAndRethrow(Throwable t) throws X {
        throw (X) t;
    }
}

class Main {
    public static void main(String[] args) { // Note no "throws" declaration
        try {
            // Do stuff that can throw IOException
        } catch (IOException ex) {
            // Pretend to throw RuntimeException, but really rethrowing the IOException
            throw ExceptionUtils.cloak(ex);
        }
    }
}

The real point of exceptions is to simplify error handling and separate it from error detection. This is in contrary to representing errors by error codes, where error handling code is scattered everywhere and every call which may fail shall be checked for return code.

If exception represents an error (which is most of the cases) usually the most reasonable way to handle it is to bail out and leave the handling to some upper layer. Rethrowing different exception should be considered if some meaningful semantics is added to it i.e., this error is an unusual system failure / temporary (networking) problem / this is client or server side error etc.

Of all error handling strategies the most ignorant is hiding or simply printing error message and going forward as nothing happened.


Sun folks wanted the code to be more explicit and forced programmers to write which exceptions may be thrown by which method. It seemed to be right move -- anybody will known what to expect in return from any method call given it's prototype (it may return value of this type or throw an instance of one of the specified classes (or it's subclass)).

But as it turned out with lots of ignorant Java programmers they now treat exception handling as if it was a language bug/"feature" which needed a workaround and write code in worst or almost worst possible way:

  • The error is handled right away in context not suitable to decide what to do with it.
  • It is displayed or ignored silently and computing continues even when further code has no chance to run properly.
  • The caller of method can not differentiate whether it finished successfully or not.

How to write the "right way" than?

  • Indicate every base class of exceptions which can be thrown in method header. AFAICR Eclipse can do it automatically.
  • Make the throw list in method prototype meaningful. Long lists are pointless and "throw Exception" is lazy (but useful when you not bother much about exceptions).
  • When writing the "wrong way" simple "throw Exception" is much better and takes less bytes than "try{ ... } catch(Exception e) { e.printStackTrace(); }".
  • Rethrow chained exception if needed.

If you want your exception to be handled outside the scope of the current method you don't need to to catch it actually, instead you add 'throws' statement to the method signature.

The try/catch statements that you've seen are only in the code where programmer explicitly decided to handle the exception in place and therefore not to throw it further.


I think developers also try to consider the importance of "doing the right thing" in a particular context. Often times for throw away code or when propagating the exception upwards wouldn't buy anything because the exception is fatal, you might as well save time and effort by "doing the wrong thing".


You would usually swallow an exception when you cannot recover from it but it is not critical. One good example is the IOExcetion that can be thrown when closing a database connection. Do you really want to crash if this happens? That's why Jakarta's DBUtils have closeSilently methods.

Now for checked exception that you cannot recover but are critical (usually due to programming errors), don't swallow them. I think exceptions should be logged the nearest as possible to the source of the problem so I would not recommend removing the printStackTrace() call. You will want to turn them into RuntimeException for the sole purpose of not having to declare these exceptions in you business method. Really it doesn't make sense to have high level business methods such as createClientAccount() throws ProgrammingErrorException (read SQLException), there is nothing you can do if you have typos in your sql or accessing bad indexes.


From experience, Swallowing an exception is harmful mostly when it's not printed. It helps to bring attention if you crash, and I'll do that deliberately at times, but simply printing the exception and continuing allows you to find the problem and fix it, and yet usually doesn't negatively effect others working on the same codebase.

I'm actually into Fail-Fast/Fail-HARD, but at least print it out. If you actually "Eat" an exception (which is to truly do nothing: {}) It will cost someone DAYS to find it.

The problem is that Java forces you to catch a lot of stuff that the developer knows won't be thrown, or doesn't care if they are. The most common is Thread.sleep(). I realize there are holes that might allow threading issues here, but generally you know that you are not interrupting it. Period.


There can be many reasons why one would use catch Exception. In many cases it is a bad idea because you also catch RuntimeExceptions - and well you don't know in what state the underlying objects will be after this happens ? That is always the difficult thing with unexpected conditions: can you trust that the rest of the code will not fail afterwards.

Your example prints the stacktrace so at least your will know what the root cause might have been. In bigger software projects it is a better idea to log these things. And lets hope that the log component does not throw exceptions either our you might end up in an infinite loop (which will probably kill your JVM).


If you have a checked exception and you don't want to handle it in a method, you should just have the method throw the exception. Only catch and handle exceptions if you are going to do something useful with it. Just logging it is not very useful in my book as users rarely have time to be reading logs looking for exceptions or know what to do if an exception is thrown.

While wrapping the exception is an option, I would not suggest you do this unless; you are throwing a different exception to match an exist interface or there really is no way such an exception should be thrown.

BTW: If you want to re throw a checked exception you can do this with

try {
   // do something
} catch (Throwable e) {
   // do something with the exception
   Thread.currentThread().stop(e); // doesn't actually stop the current thread, but throws the exception/error/throwable
}

Note: if you do this, you should make sure the throws declaration for the method is correct as the compiler is unable to do this for you in this situation.


because it is a best practice. I thought everybody knew.
but the cold truth is that nobody really understands how to work with exceptions. The C error handing style made so much more sense.

참고URL : https://stackoverflow.com/questions/921471/why-do-java-people-frequently-consume-exceptions-silently

반응형