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


81

전에는 심각한 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);
        }
    }

56
나는 스택 추적이 인쇄 될 때 정말 조용하지 않다고 말하고 싶습니다 :)
willcodejavaforfood

13
Isaac Waller의 말을 인용하겠습니다. "하지만 프로그램이 종료되지 않고 계속 진행됩니다. 대부분 정의되지 않은 상태 일 것입니다."
Sake

15
@willcodejavaforfood, 귀하의 의견은 너무 많은 표를 얻었으며 일반적인 Java 사고 방식에 대해 더 많은 질문을 받았습니다.
Sake

13
@willcodejavaforfood-호출자의 관점에서 보면 조용합니다. 발신자는 무슨 일이 일어 났는지 전혀 모릅니다. 그게 의도 된 것이라면 괜찮지 만 일반적으로 나쁜 소식입니다. 또한-애플릿에서 일어나는 일에 대해 생각해보십시오. 사용자는 출력을 볼 수 없습니다 (자바 콘솔이 열려 있지 않는 한). 좋아, 그래서 아무도 더 이상 애플릿을 사용하지 않는다;) servletm과 비슷하지만 최종 사용자는 아무 일도 일어나지 않았 음을 알지 못합니다. 그냥 로그에 숨겨집니다.
Scott Stanchfield

4
Java에서 예외를 던지는 것은 대부분의 Java 코더가이를 무시할 정도로 널리 퍼져 있습니다. 올바른 오류 포착을 수행하면 훨씬 더 많은 코드를 작성해야하기 때문입니다. 기본적으로 모든 Java 프로그래머는 게으 르기 때문에이 작업을 수행합니다.
Trevor Boyd Smith

답변:


203

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

"남자가 총에 맞습니다.

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

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

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

더 나은 것은 :

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

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

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

질문에 답하기 :

  1. 무지.
      +
  2. 나태

편집하다:

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

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

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

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


2
예외를 삼키는 것은 실패하지 않습니다. 빨리 실패해도 상관 없습니다. 반면에 메서드 계약에 숫자 문자열 인 매개 변수가 있고이를 정수로 구문 분석하는 경우 ParseException을 삼킬 수 있습니다. 특정 기능을 작성하는 경우 실패한 기능에 대한 사용자 지정 예외를 정의한 다음 예외를 포착하고 사용자 지정 예외를 throw합니다 (원래 예외를 인수로 사용). 그런 다음 의미있는 동작이 발생할 수있는 곳으로 빠르게 실패 할 수 있습니다 (사용자에게 표시, 이메일 보내기, 로그 만 남기기,이 서버 스레드 종료 등).
JeeBee

21
잠깐만 요 ... 먼저 웃지 마세요 ... 좋아요 ... 지금까지 본 질문에 대한 가장 재미있는 답변이었습니다. 요점을 매우 많이 이해합니다. 처리를 위해 "체인 위로"예외를 전달하는 것이 매우 도움이 될 수 있지만, 최소한 예외를 먼저 포착 한 다음 전달하여 유용한 정보가 포함될 수 있도록하는 것이 좋습니다.
Mr. Will

예외는 오류가 아닙니다. 예외를 던지는 남자는 총에 맞고 사건을 메모에 자세히 적고 가장 가까운 살인 부대로 날아가도록 훈련 된 운반 비둘기에 붙인다.
Jherico

13
@Oscar, 가능하다면 +100. 잘못된 예외 처리는 게으름이 아니라 무지와 악의의 결과입니다. 게으름 = 가능한 한 적은 노력. 예외 처리의 어리 석음은 더 많은 작업을 유발하지만 감소 시키지는 않습니다. 물론 일반적으로 다른 사람에게 더 많은 작업을 유발하기 때문에 "게으른"것처럼 보입니다.
James Schek

1
나는 당신의 요점 오스카를 보았지만 예외를 처리하거나 기록하는 것은 예외가 발생했음을 보여줍니다. 체인을 백업하는 동안 끝까지 던지면 궁극적으로 예외를 호출 한 메서드를 알 수 있습니다.
Mauro

33

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

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


2
동의합니다. 주어진 예제는 // FIXME : 주석이 제거 된 Eclipse의 기본 빠른 수정처럼 보입니다.
JeeBee

2
글쎄, 당신은 "이건 잘못된 형태입니다. 의심 할 여지가 없습니다. "라고 말했고 저는 100 % 동의합니다. 그러나 다른 답변과 의견은 Java 개발자의 매우 큰 부분 (내가 믿는다)의 철학에 대해 매우 호기심을 느끼게합니다.
Sake

4
Eclipse가 과감한 작업을 수행하기를 정말 바랍니다. 다음과 같이 e.printStackTrace (); System.exit (1);
Adam Jaskiewicz

4
RuntimeException으로 다시 throw하는 catch 본문을 생성하도록 IDE 설정을 변경했습니다. 그것은 훨씬 더 나은 기본값입니다.
Esko Luontola

6
예외가 발생해서는 안된다고 확신하는 경우, 의도를 문서화하는 방법으로 보통 RuntimeException 대신 AssertionError를 발생시킵니다.
Esko Luontola

20

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


1
프로 프로그래머가 프로덕션이 아닌 블로그 나 잡지에 잘못된 코드를 작성해도 괜찮습니까? 이드는 오히려 프로덕션에서 나쁜 코드를 작성합니다. 정말 똑똑한 사람이 printStackTrace를 사용하고 있다면 사람들이 그것을 사용하도록 설득합니다. 나는 예외 코드가 8 자 더 길다는 것을 이해하지만 ...
IAdapter

8
@ABCDE : 나는 완전히 동의하지 않습니다. 프로덕션에서 나쁜 코드를 작성하고 싶습니까? 작동해야하는 코드입니다! 블로그와 잡지 기사는 요점을 설명해야합니다. 오류 처리가 중요하지 않다면 혼란 스러울 수 있습니다. 많은 작가가 매우 단순화 된 오류 처리를 사용하거나 기사에서 전혀 사용하지 않습니다. 이것은 따라야 할 예가 아닙니다.
Bill the Lizard

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

7
그러나 프로그램은 종료되지 않고 계속 진행되며 대부분 정의되지 않은 상태 일 수 있습니다.
Isaac Waller

5
예외 유형을 안다면 상태가 어떻게 정의되지 않습니까? 그것은 귀여운 작은 인용문이지만 일반적으로 프로그램은 계속 진행할 수 있고 계속해야합니다. 예외로 인해 전체 응용 프로그램이 충돌하는 것을 원하지 않습니다. 사용자에게 무엇이든 다시 수행하도록 요청하십시오.
GreenieMeanie

2
예외가 가장 바깥 쪽 수준에서 제대로 처리되면 응용 프로그램이 충돌하지 않습니다.
Sake

2
예외의 절반 이상은 "RuntimeExceptions"로, 하나만있는 것처럼 들립니다. 그리고 그것은 침묵하지 않으며 잡히지 않은 RutimeException은 스택 추적을 인쇄하고 프로그램을 중단시킵니다.
Bill K

@greenieMeanie 일반적으로 개발 단계에서는 사소한 문제로 인해 충돌이 발생하기를 원합니다. 개발자가 전화를 망쳐 놓지 못하게해서는 안됩니다. 아무것도 용서하지 마십시오. 반면에, 당신이 그것을 발송할 때, 당신은 반대로 가고 싶습니다. 모든 예외를 눈에 띄지 않게 기록하고 최선을 다해 복구하고 계속하십시오 (Java가 정말 능숙합니다).
Bill K

12

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

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

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

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

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

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


3
특히이 질문에 대해 이유 1이 이유 2보다 훨씬 더 일반적이라고 생각합니다
matt b

2
@matt b, 동의했습니다. 게으름은 내가 요즘 수정하는 버그의 상당 부분을 담당합니다.
JaredPar

오류 코드를 무시하는 것은 더 빨리 볼 수 있으며 상용구 코드를 훨씬 적게 사용합니다!
gbjbaanb

11

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

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


17
그들은 실패한 실험이 아닙니다. 사실 나는 그들을 좋아한다! 다른 답변 프로그래머가 지적했듯이 프로그래머는 게으르고 오류 사례를 무시하는 경향이 있습니다. 체크 된 예외는 당신이 그들을 다루도록 강요하기 때문에 전반적으로 더 나은 코드를 갖게 될 것입니다. (프로그래머가 자동으로 무시하지 않는 경우). 또한, 당신이 게으르지 않더라도, 컴파일러가 그렇게하라고 할 것이기 때문에 중요한 예외를 캐치하는 것을 잊을 수 없습니다 ...
Malax

5
확인 된 예외는 여러 가지 이유로 실패합니다. 일부를 확인하십시오. mindview.net/Etc/Discussions/CheckedExceptions
dfa

2
+1은 더 이상 동의 할 수 없습니다. 확인 된 예외는 종종 코드를 안전하게 만들고 이것이 그 방법의 한 예입니다.
cletus

2
확인 된 예외는 확실히 완벽하지는 않지만 때때로 일이 계획에 따라 진행되지 않는 현실에 직면하게합니다. 예외 그냥 아무 잘못없는 경우 우리는 완벽한 세상에서 살고 척하려고하는 비는 - 확인
mcjabberz

2
@Peter Lawrey : 확인 된 예외는 실패한 것입니다. 놀라운 스윙 프레임 워크와 함께 온 사람들처럼 매우 똑똑한 사람들이 그들에게 토하고 사용을 거부하기 때문입니다. 그리고 저는 Joshua Bloch와 같은 사람들이나 Spring 프레임 워크 뒤에있는 사람들이 "올바르게 사용하는 방법을 모른다"고 의심합니다. 물론 확인 된 예외를 올바르게 처리 할 수 있습니다 . 진짜 망가진 점은 누군가 어딘가에서 던지는 것이 허용되는 관행이라고 생각했다는 것입니다.
SyntaxT3rr0r

6

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

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

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

그런 성격의 기사를 쓰는 사람들은 합리적인 신호 대 잡음비를 유지해야하며, 오히려 공정하게, 그것은 당신이 개발하는 언어에 대한 몇 가지 기본 사항을 알고 있다고 가정해야한다는 것을 의미합니다. 오류를 올바르게 처리하는 방법 및 기타 여러 가지. 기사를 발견하고 적절한 오류 검사가 부족한 것을 발견하면 괜찮습니다. 이러한 아이디어를 프로덕션 코드에 통합 할 때 (물론 정확한 코드 자체는 절대로하지 않습니다. 맞죠?) 작성자가 현명하게 빠뜨린 모든 비트와 멍청이를 가장 적절한 방식으로 다룰 것입니다. 개발중인 제품에 적합합니다.

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


그러나 사용하여 고급 기사를 작성하는 try {...} catch (IOException e) {}것은 어리석은 일입니다 (TODO는 도움이되지 않습니다). 많은 초보자들이 똑같이하도록 오해 할 것입니다. 또한 대부분의 경우 옳은 것보다 작성throws IOException 하는 것이 훨씬 더 많습니다 . 아마도 논문 당 한 번은 가능하지 않을 수 있으며 throw wrap(e)정의하는 데 지루하지 않은 글쓰기 wrap가 좋은 해결책입니다. 자바에서 가장 먼저 기대했던 것 중 하나는 조용히 삼키는 것이 끔찍한 일이며 일시적으로도하지 않기 때문에 세심한주의를 기울이고 있습니다 (장기적으로는 충돌조차도 훨씬 좋습니다).
maaartinus

5

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

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

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


3

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

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

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


3

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

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

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

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


2

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

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


2

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

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

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

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


3
캐치 (Throwable)를보고 움찔했다.
Bill the Lizard

2
물론입니다. 나는 그냥 catch (Throwable)를 사용하거나 코드에서 Throwable을 던집니다. "실제"코드는 그것을 포함해서는 안됩니다! 기간.
Malax

동의합니다. 전에 본 적이있어서 움찔합니다. 다른 개발자가 당신이 catch (Throwable)를 작성했다는 것을 알게된다면 너무 멀리 간 것입니다! :)
Bill the Lizard

1
코드가 프로세스를 종료하더라도 최상위 수준에서 catch (Throwable)를 원합니다. 하나의 실이 빠진 상태에서 허블을 시도하는 것은 최선의 생각이 아닐 수 있습니다.
Tom Hawtin-tackline

2

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

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


2

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

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

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

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

나는 100 %이 문제에 대해 Bruce Eckel을 신뢰하지 않을 것입니다. :)
CurtainDog

2

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

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

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


1
IMHO, 런타임 오류와 같은 예외를 포착하고 다시 던질 수있는 언어 속기가 있어야합니다. 이러한 속기 표기는 이러한 예외가 "예기치 않은"조건을 나타내는 것으로 간주되어야한다는 것을 코드와 동작 모두에서 명확하게합니다. 삼키는 것은 나쁘다. 예외가 발생하면 뭔가 심각한 문제 이고 호출 코드가 이에 대해 알아 내야하기 때문이다.
supercat 2014-04-04

supercat : 그 아이디어가 마음에 들지만 확인 된 예외의 (IMO 의심스러운) 이점을 취소 할 수 있습니다.
Erich Kitzmueller 2014

검사가 예외 클래스가 아닌 catch / throw 사이트 및 예외 인스턴스의 특성이면 더 좋을 것입니다. 따라서 검사 된 예외는 동일한 클래스의 검사되지 않은 예외로 전파 될 수 있지만 랩-앤-리스로도 크게 개선 될 것입니다. 새로운 기능으로 쉽게 추가 할 수 있습니다. 자체적으로 확인 된 예외를 던질 수있는 메서드가 동일한 예외를 던지는 것으로 선언 되었지만 실제로는 그렇게 할 것으로 예상되지 않는 다른 메서드를 호출하는 경우에 특히 유용합니다 . 후자의 방법 중 하나가 던지면 ...
supercat 2014-04-09

... 외부 메서드에서 throw 된 예외를 처리 할 것으로 예상되는 호출자는 호출자가 예상 한 조건을 나타내지 않기 때문에 내부 메서드에서 throw 된 예외를 잡아서는 안됩니다. 내가 처음부터 런타임 프레임 워크를 디자인한다면 체크 된 예외와 체크되지 않은 예외에 대해 다른 메커니즘을 사용하여 체크 된 예외는 성공적인 함수 호출에 약간의 오버 헤드를 추가하지만 체크되지 않은 예외보다 throw 될 때 오버 헤드가 훨씬 적습니다. , catch-as-checked 예외에는 스택 추적이 없습니다).
supercat 2014-04-09

1

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

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


1

게으른 연습-그게 다가 아닙니다.

일반적으로 손가락 작업을 늘리기보다는 예외에 대해 정말로 신경 쓰지 않을 때 수행됩니다.


1

확인 된 예외를 다시 던지는 것이 더 나은 생각이라는 데 동의하지 않습니다. 잡는 것은 취급을 의미합니다. 다시 던져야한다면 잡으면 안됩니다. 이 경우 메서드 서명에 throws 절을 추가합니다.

확인되지 않은 예외에 체크 된 예외를 래핑하는 것이 허용된다고 말할 수 있습니다 (예 : Spring이 체크 된 SQLException을 체크되지 않은 계층의 인스턴스로 래핑하는 방식).

로깅은 처리로 간주 될 수 있습니다. 콘솔에 쓰는 대신 log4j를 사용하여 스택 추적을 기록하도록 예제를 변경 한 경우 허용됩니까? 큰 변화는 아닙니다, IMO.

진짜 문제는 예외적이고 수용 가능한 복구 절차로 간주되는 것입니다. 예외에서 복구 할 수없는 경우 최선의 방법은 실패를보고하는 것입니다.


1

확인되지 않은 예외에 확인 된 예외를 래핑하지 마십시오.

당신이해서는 안된다고 생각하는 예외를 다루고 있다면 내 조언은 당신이 아마도 잘못된 추상화 수준에서 일하고 있다는 것입니다.

자세히 설명하겠습니다. 확인 된 예외와 확인되지 않은 예외는 매우 다른 두 가지입니다. 확인 된 예외는 오류 코드를 반환하는 이전 방법과 유사합니다. 예, 오류 코드보다 처리하기가 다소 고통 스럽지만 장점도 있습니다. 확인되지 않은 예외는 프로그래밍 오류 및 심각한 시스템 오류입니다. 즉, 예외적 인 예외입니다. 예외가 무엇인지 설명하려고 할 때 많은 사람들이이 두 가지 매우 다른 경우의 차이를 인식하지 못하기 때문에 완전히 엉망이됩니다.


AssertionError의 래핑은 저에게 공감합니다. AssertionError는 IMO에 적용되는 추상화입니다.
Sake

자세히 설명하겠습니다. 확인 된 예외와 확인되지 않은 예외는 매우 다른 두 가지입니다. 확인 된 예외는 오류 코드를 반환하는 이전 방법과 유사합니다. 예, 오류 코드보다 처리하기가 다소 고통 스럽지만 장점도 있습니다. 확인되지 않은 예외는 프로그래밍 오류 및 심각한 시스템 오류입니다. 즉, 예외적 인 예외입니다. 예외가 무엇인지 설명하려고 할 때 많은 사람들이이 두 가지 매우 다른 경우의 차이를 인식하지 못하기 때문에 완전히 엉망이됩니다.
CurtainDog 2009-06-10

아마 나는 당신이 말했듯이 완전한 혼란에 빠지는 사람들 중 하나 일 것입니다. 그러나 내 진짜 요점은 중단 할 수있는 선택권이있는 동안 실행을 계속하도록 허용하는 이유입니다. (AssertionError 또는 원하는 경우 추가 예외를 포함하도록 인터페이스를 변경하십시오.
Sake

1
이 답변의 주요 주장에 더 동의하지 않을 수 없습니다. 정교함은 장점이 있습니다.
Lawrence Dol

@CurtainDog : 확인 된 예외는 "예상 된"문제에 대한 것입니다. 만약 x 메소드가 FooException을 던지고 (체크 됨) x를 호출하는 메소드 y가 그러한 케이스가 발생할 것으로 예상하지 않는다면, 그러한 케이스 발생하면 예상치 못한 문제 를 나타냅니다 . a를 기대하는 호출 스택 위에 뭔가가 발생하더라도 FooException현재 상황은 a FooException가 던져 질 때 업스트림 호출자가 기대하는 것과 일치하지 않습니다 .
supercat 2014-04-04

1

아직이 트릭을 배우지 않았기 때문에 :

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);
        }
    }
}

이것은 좋은 속임수이지만 개인적으로 나는 'throw new ServiceUnavailableException (ex)'과 같은 원인으로 더 구체적인 예외를 던지는 것을 선호합니다
Greg

Apache ExceptionUtils의 rethrow 메소드는 정확히 이것을 수행합니다. 좋은 속임수입니다. github.com/apache/commons-lang/blob/master/src/main/java/org/…
Lluis Martinez

1

예외의 진짜 요점은 오류 처리를 단순화하고 오류 감지와 분리하는 것입니다. 이는 오류 코드로 오류를 나타내는 것과는 반대로 오류 처리 코드가 어디에나 흩어져 있고 실패 할 수있는 모든 호출에서 반환 코드를 확인해야합니다.

예외가 오류 (대부분의 경우)를 나타내는 경우 일반적으로이를 처리하는 가장 합리적인 방법은 구제 조치를 취하고 처리를 일부 상위 계층에 맡기는 것입니다. 의미있는 의미가 추가 된 경우 다른 예외를 다시 던지는 것을 고려해야합니다. 즉,이 오류는 비정상적인 시스템 오류 / 일시적인 (네트워킹) 문제 / 클라이언트 또는 서버 측 오류 등입니다.

모든 오류 처리 전략 중에서 가장 무지한 것은 오류 메시지를 숨기거나 단순히 인쇄하고 아무 일도 일어나지 않은 상태에서 진행하는 것입니다.


썬 사람들은 코드가 더 명확 해지기를 원했고 프로그래머는 어떤 방법으로 어떤 예외를 던질 수 있는지 작성하도록 강요했습니다. 올바른 움직임 인 것처럼 보였습니다. 프로토 타입이 주어지면 모든 메서드 호출에서 어떤 결과를 기대할지 누구나 알 수 있습니다 (이 유형의 값을 반환하거나 지정된 클래스 중 하나의 인스턴스 (또는 하위 클래스)를 던질 수 있음).

그러나 많은 무지한 자바 프로그래머들과 함께 밝혀 졌기 때문에 그들은 이제 예외 처리를 해결 방법이 필요한 언어 버그 / "기능"인 것처럼 처리하고 최악의 또는 거의 최악의 가능한 방법으로 코드를 작성합니다.

  • 오류는 처리 할 작업을 결정하는 데 적합하지 않은 컨텍스트에서 즉시 처리됩니다.
  • 자동으로 표시되거나 무시되며 추가 코드가 제대로 실행될 수없는 경우에도 컴퓨팅이 계속됩니다.
  • 메서드 호출자는 성공적으로 완료되었는지 여부를 구별 할 수 없습니다.

"올바른 방법"을 쓰는 방법보다?

  • 메소드 헤더에서 발생할 수있는 모든 기본 예외 클래스를 나타냅니다. AFAICR Eclipse는이를 자동으로 수행 할 수 있습니다.
  • 메서드 프로토 타입의 throw 목록을 의미있게 만듭니다. 긴 목록은 무의미하며 "예외 발생"은 게으르다 (그러나 예외에 대해 많이 신경 쓰지 않을 때 유용함).
  • "잘못된 방법"을 작성할 때 간단한 "예외 발생"이 "try {...} catch (Exception e) {e.printStackTrace ();}"보다 훨씬 낫고 적은 바이트를 사용합니다.
  • 필요한 경우 체인 예외를 다시 발생시킵니다.

0

예외가 현재 메서드의 범위 밖에서 처리되기를 원한다면 실제로 그것을 잡을 필요가 없습니다. 대신에 메서드 서명에 'throws'문을 추가합니다.

여러분이 본 try / catch 문은 프로그래머가 명시 적으로 예외를 처리하기로 결정한 코드에만 있으므로 더 이상 발생하지 않습니다.


1
사실이 아닙니다. 인터페이스 메서드를 구현하거나 'throws'선언이없는 슈퍼 클래스 메서드를 재정의하는 경우 하나만 추가 할 수 없습니다. 이러한 경우에는 RuntimeException에 예외를 래핑하거나 삼켜야합니다.
Martin McNulty

0

개발자들은 특정 상황에서 "올바른 일을하는 것"의 중요성을 고려하려고합니다. 종종 코드를 버리거나 예외를 위쪽으로 전파하는 경우 예외가 치명적이기 때문에 아무 것도 구매하지 않을 때 "잘못된 작업을 수행"하여 시간과 노력을 절약 할 수 있습니다.


0

일반적으로 복구 할 수없는 경우 예외를 삼키지 만 중요하지는 않습니다. 한 가지 좋은 예는 데이터베이스 연결을 닫을 때 발생할 수있는 IOExcetion입니다. 이런 일이 발생하면 정말 충돌 하시겠습니까? 이것이 Jakarta의 DBUtils에 closeSilently 메서드가있는 이유입니다.

이제 복구 할 수 없지만 중요한 (일반적으로 프로그래밍 오류로 인해) 확인 된 예외의 경우 삼키지 마십시오. 예외는 가능한 한 문제의 원인에 가장 가깝게 기록되어야한다고 생각하므로 printStackTrace () 호출을 제거하지 않는 것이 좋습니다. 비즈니스 메소드에서 이러한 예외를 선언 할 필요가없는 유일한 목적으로이를 RuntimeException으로 전환 할 수 있습니다. 실제로 createClientAccount ()와 같은 고급 비즈니스 메서드가 ProgrammingErrorException (SQLException 읽기)을 throw하는 것은 이치에 맞지 않습니다. SQL에 오타가 있거나 잘못된 인덱스에 액세스하는 경우 수행 할 수있는 작업이 없습니다.


0

경험상 예외를 삼키는 것은 인쇄되지 않을 때 대부분 해 롭습니다. 충돌이 발생하면주의를 환기시키는 데 도움이되며 때로는 의도적으로 그렇게 할 것이지만 단순히 예외를 인쇄하고 계속하면 문제를 찾아 고칠 수 있지만 일반적으로 동일한 코드베이스에서 작업하는 다른 사람들에게 부정적인 영향을 미치지는 않습니다. .

나는 실제로 Fail-Fast / Fail-HARD에 있지만 적어도 그것을 인쇄하십시오. 실제로 예외를 "먹는"경우 (진정으로 아무것도하지 않으려는 경우 : {}) 누군가 그것을 찾는 데 며칠이 걸립니다.

문제는 자바가 개발자가 던지지 않을 것이라는 것을 알고 있거나 그럴 경우 신경 쓰지 않는 많은 것을 잡도록 강요한다는 것입니다. 가장 일반적인 것은 Thread.sleep ()입니다. 여기에 스레딩 문제를 허용 할 수있는 구멍이 있다는 것을 알고 있지만 일반적으로 방해하지 않는다는 것을 알고 있습니다. 기간.


0

catch Exception을 사용하는 데는 여러 가지 이유가있을 수 있습니다. 많은 경우에 RuntimeExceptions도 포착하기 때문에 나쁜 생각입니다. 그리고이 일이 발생한 후 기본 객체가 어떤 상태가 될지 잘 모릅니다. 예상치 못한 상황에서는 항상 어려운 일입니다. 나머지 코드가 나중에 실패하지 않을 것이라고 믿을 수 있습니까?

귀하의 예제는 스택 추적을 인쇄하므로 최소한 근본 원인이 무엇인지 알 수 있습니다. 더 큰 소프트웨어 프로젝트에서는 이러한 사항을 기록하는 것이 좋습니다. 그리고 로그 구성 요소가 예외를 throw하지 않기를 바랍니다. 무한 루프가 될 수 있습니다 (아마도 JVM을 죽일 것입니다).


0

확인 된 예외가 있고 메서드에서 처리하지 않으려면 메서드가 예외를 throw하도록해야합니다. 유용한 일을하려는 경우에만 예외를 포착하고 처리하십시오. 로그 만 기록하는 것은 내 책에서별로 유용하지 않습니다. 사용자가 예외를 찾아 로그를 읽을 시간이 거의 없거나 예외가 발생하면 어떻게해야하는지 알기 때문입니다.

예외를 래핑하는 것은 옵션이지만, 그렇지 않으면 이렇게하지 않는 것이 좋습니다. 존재하는 인터페이스와 일치하기 위해 다른 예외를 던지고 있거나 실제로 그러한 예외를 던질 방법이 없습니다.

BTW : 체크 된 예외를 다시 던지고 싶다면 다음과 같이 할 수 있습니다.

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
}

참고 :이 경우 컴파일러가이 상황에서이를 수행 할 수 없으므로 메서드에 대한 throws 선언이 올바른지 확인해야합니다.


Just FTR : Thread#stop()그동안 더 이상 사용되지 않고 비활성화되었습니다 (를 발생시킵니다 UnsupportedOperationException).
maaartinus

-2

모범 사례이기 때문입니다. 모두가 알고 있다고 생각했습니다.
그러나 냉담한 진실은 아무도 예외를 처리하는 방법을 정말로 이해하지 못한다는 것입니다. C 오류 처리 스타일이 훨씬 더 의미가 있습니다.


1
많은 개발자가 예외를 생성하지 않는다고해서 "오류 반환"이 더 나아지지는 않습니다. 오류를 처리하는 C 방식은 여전히 ​​끔찍하게 오류가 발생하기 쉬운 (말장난 의도) 메커니즘이었습니다. 예외를 삼키는 것은 (이 예제에서는 조용히하지 않고) 반환 값을 확인하지 않고 C에서 함수를 호출하는 것과 유사합니다. 최종 결과는 동일합니다. 프로그램이 "실패"합니다. 이 예제는 Java 오류 처리를 나쁜 C로 만드는 경우 일뿐입니다.
Lawrence Dol
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.