확인 된 예외에 대한 사례


456

몇 년 동안 나는 다음 질문에 대한 적절한 대답을 얻을 수 없었습니다. 왜 일부 개발자는 확인 된 예외에 대해 그렇게합니까? 나는 수많은 대화를 나누고 블로그에서 글을 읽고 Bruce Eckel이 말한 것을 읽었습니다.

나는 현재 새로운 코드를 작성하고 있으며 예외를 처리하는 방법에 매우주의를 기울이고 있습니다. "체크 된 예외를 좋아하지 않습니다"라는 군중의 관점을 보려고하는데 여전히 볼 수 없습니다.

내가 가진 모든 대화는 같은 질문으로 대답하지 않고 끝납니다 ... 설정하겠습니다.

일반적으로 (Java가 설계된 방식에서)

  • Error 잡히지 말아야 할 것들입니다 (VM에는 땅콩 알레르기가 있고 누군가 땅콩 항아리를 떨어 뜨 렸습니다)
  • RuntimeException 프로그래머가 잘못한 일을위한 것입니다 (프로그래머가 배열의 끝에서 나갔습니다)
  • Exception(제외 RuntimeException)는 프로그래머가 제어 할 수없는 것들을위한 것입니다 (파일 시스템에 쓰는 동안 디스크가 가득 차고 프로세스의 파일 핸들 한계에 도달했으며 더 이상 파일을 열 수 없습니다)
  • Throwable 단순히 모든 예외 유형의 부모입니다.

내가 듣는 일반적인 주장은 예외가 발생하면 모든 개발자가 프로그램을 종료한다는 것입니다.

내가 듣는 또 다른 일반적인 주장은 확인 된 예외로 인해 코드를 리팩터링하기가 더 어렵다는 것입니다.

"내가하려고하는 것은 모두 종료이다"라는 주장에 대해, 나는 당신이 나가더라도 합리적인 오류 메시지를 표시해야한다고 말합니다. 오류를 처리하는 데 어려움을 겪고 있다면 이유를 명확하게 표시하지 않고 프로그램이 종료 될 때 사용자는 지나치게 만족하지 않을 것입니다.

"리팩토링하기가 어렵습니다"군중의 경우 적절한 추상화 수준이 선택되지 않았 음을 나타냅니다. 오히려 방법은 발생을 선언보다 IOException상기가 IOException더 진행되는 것에 대해 적합 예외로 변환한다.

Main으로 줄 바꿈하는 데 문제가 없으며 catch(Exception)(또는 경우 catch(Throwable)에 따라 프로그램을 정상적으로 종료 할 수 있도록 보장하지만 항상 필요한 특정 예외를 잡습니다. 에러 메시지.

사람들이 대답하지 않는 질문은 다음과 같습니다.

만약 당신이 RuntimeException 서브 클래스 대신 서브 클래스 를 던진다면 Exception 무엇을 잡아야하는지 어떻게 알 수 있습니까?

대답이 잡히면 Exception시스템 예외와 같은 방식으로 프로그래머 오류도 처리합니다. 그것은 나에게 잘못 보인다.

잡으면 Throwable시스템 예외와 VM 오류 등을 같은 방식으로 처리합니다. 그것은 나에게 잘못 보인다.

대답은 당신이 알고있는 예외 만 잡는다는 것입니다. 그렇다면 어떤 예외가 발생했는지 어떻게 알 수 있습니까? 프로그래머 X가 새로운 예외를 던지고 그것을 포착하지 못한 경우 어떻게됩니까? 그것은 나에게 매우 위험한 것 같습니다.

스택 추적을 표시하는 프로그램이 잘못되었다고 말할 수 있습니다. 확인 된 예외를 좋아하지 않는 사람들은 그렇게 느끼지 않습니까?

따라서 확인 된 예외가 마음에 들지 않으면 왜 응답하지 않는 질문에 대답하지 않습니까?

편집 : 나도 모델을 사용하는 경우에 대한 조언을 찾고 있지 않다, 내가 무엇을 찾고있는 것은 사람들이에서 연장 RuntimeException되지에서 연장처럼 그들이 때문에 Exception및 / 또는 왜 그들은 예외를 캐치 한 다음 다시 발생 RuntimeException하지 않고 추가가 발생보다 그들의 방법. 확인 된 예외를 싫어하는 동기를 이해하고 싶습니다.


46
나는 이것이 완전히 주관적이라고 생각하지 않습니다. 모든 사람이 자신을 위해 무엇을 결정할 것인지보다는 특정 용도로 사용하도록 설계된 언어 기능입니다. 그리고 그것은 특히 논쟁의 여지가 없으며 사람들이 쉽게 생각해 낼 수있는 특정 반박을 미리 해결합니다.
Gareth

6
어서 언어 기능으로 볼 때이 주제는 객관적인 방식으로 접근했으며 접근 할 수 있습니다.
Kurt Schelfthout

6
@cletus "자신의 질문에 답하기"대답이 있다면 질문하지 않았을 것입니다!
TofuBeer

8
좋은 질문입니다. C ++에는 확인 된 예외가 없으며 제 생각에는 예외 기능을 사용할 수 없게 만듭니다. 무언가를 던질 수 있는지 알지 못하기 때문에 모든 단일 함수 호출을 포착 해야하는 상황이 발생합니다.
Dimitri C.

4
확인 된 예외에 대해 내가 알고있는 가장 강력한 주장 은 원래 Java에는 없었으며 도입되었을 때 JDK에서 수백 가지 버그를 발견했다는 것입니다. 이것은 Java 1.0 이전의 것입니다. 나는 개인적으로 그들 없이는 없을 것이며, Bruce Eckel 및 다른 사람들과 폭력적으로 동의하지 않습니다.
Lorne의 후작

답변:


277

나는 당신이했던 것과 같은 Bruce Eckel 인터뷰를 읽은 것 같아요. 항상 나를 괴롭 혔습니다. 실제로, 인터뷰 대상자는 .NET과 C #의 MS 천재 인 Anders Hejlsberg가 인터뷰 대상자에 의해 주장되었습니다.

http://www.artima.com/intv/handcuffs.html

내가 Hejlsberg와 그의 작품을 좋아하는 팬이지만,이 주장은 항상 나를 가짜로 부딪쳤다. 기본적으로 다음과 같이 요약됩니다.

"확인 된 예외는 프로그래머가 예외를 잡아서 무시함으로써 남용하기 때문에 문제가 숨겨 지거나 무시되어 사용자에게 표시 될 수 있기 때문에 예외입니다."

에 의해 "그렇지 않으면 사용자에게 제공" 당신이 런타임 예외를 사용하는 경우 내 말은 게으른 프로그래머는 그냥 (빈 catch 블록으로 잡는 대) 무시하고 사용자가 표시됩니다.

논쟁의 요약은 "프로그래머는 그것들을 제대로 사용하지 못하고 제대로 사용하지 않는 것이 그들을 갖지 않는 것보다 나쁘다"는 것이다.

이 주장에는 약간의 진실이 있으며 실제로 Java에서 운영자 재정의를하지 않는 Goslings 동기가 비슷한 주장에서 비롯된 것 같습니다. 프로그래머가 종종 학대를 당하기 때문에 프로그래머를 혼란스럽게합니다.

그러나 결국, 나는 그것이 Hejlsberg 's와 아마도 사소한 결정이 아니라 부족을 설명하기 위해 만들어진 사후 주장에 대한 가짜 주장을 발견합니다.

확인 된 예외를 과도하게 사용하는 것은 나쁜 일이며 사용자가 부주의하게 처리하는 경향이 있지만 API를 올바르게 사용하면 API 프로그래머가 API 클라이언트 프로그래머에게 큰 이점을 줄 수 있습니다.

이제 API 프로그래머는 모든 곳에서 확인 된 예외를 발생시키지 않도록주의해야합니다. 그렇지 않으면 클라이언트 프로그래머를 귀찮게합니다. 매우 게으른 클라이언트 프로그래머는 (Exception) {}Hejlsberg가 경고하고 모든 혜택을 잃어 버리고 지옥이 뒤 따르는 것에 따라 잡을 것입니다. 그러나 어떤 상황에서는 잘 확인 된 예외를 대신 할 수있는 방법이 없습니다.

나에게 고전적인 예는 파일 열기 API입니다. 언어 역사 (파일 시스템 이상)의 모든 프로그래밍 언어에는 파일을 열 수있는 API가 있습니다. 이 API를 사용하는 모든 클라이언트 프로그래머는 열려고하는 파일이 존재하지 않는 경우를 처리해야한다는 것을 알고 있습니다. 이 API를 사용하는 모든 클라이언트 프로그래머 는이 사례를 처리 해야한다는 것을 알아야 합니다. API 프로그래머가 주석만으로 처리해야 함을 알릴 수 있거나 실제로 클라이언트가 처리하도록 요구할 수 있습니다 .

C에서 관용구는 다음과 같습니다.

  if (f = fopen("goodluckfindingthisfile")) { ... } 
  else { // file not found ...

여기서 fopen0과 C를 반환하여 실패를 나타냅니다 (어리석게도) 0을 부울로 취급하고 기본적 으로이 관용구를 배우면 괜찮습니다. 그러나 당신이 멍청하고 관용구를 배우지 않으면 어떻게 될까요? 물론, 당신은 시작합니다

   f = fopen("goodluckfindingthisfile");
   f.read(); // BANG! 

어려운 방법을 배우십시오.

여기서는 강력한 형식의 언어에 대해서만 이야기하고 있습니다. 강력한 형식의 언어로 API가 무엇인지에 대한 명확한 아이디어가 있습니다. 각 언어에 대해 명확하게 정의 된 프로토콜과 함께 사용할 수있는 기능 (메소드)입니다.

명확하게 정의 된 프로토콜은 일반적으로 메소드 서명으로 정의됩니다. 여기서 fopen은 문자열 (또는 C의 경우 char *)을 전달해야합니다. 다른 것을 주면 컴파일 타임 오류가 발생합니다. 프로토콜을 따르지 않았습니다. API를 올바르게 사용하고 있지 않습니다.

일부 (불분명 한) 언어에서는 반환 유형도 프로토콜의 일부입니다. fopen()변수에 할당하지 않고 일부 언어에서 동등한 언어 를 호출하려고 하면 컴파일 타임 오류가 발생합니다 (void 함수에서만 가능합니다).

: 내가 만들려고 점이다 정적 타입 언어에서 API 프로그래머는 명백한 실수를하는 경우 컴파일에서 자신의 클라이언트 코드를 방지하여 제대로 API를 사용하도록 클라이언트를 권장합니다.

(루비와 같이 동적으로 유형이 지정된 언어에서는 파일 이름으로 플로트와 같은 것을 전달할 수 있으며 컴파일됩니다. 메소드 인수를 제어하지 않더라도 사용자에게 확인 된 예외가 발생하는 이유는 무엇입니까? 여기에 작성된 인수는 정적으로 유형이 지정된 언어에만 적용됩니다.)

그렇다면 확인 된 예외는 어떻습니까?

다음은 파일을 여는 데 사용할 수있는 Java API 중 하나입니다.

try {
  f = new FileInputStream("goodluckfindingthisfile");
}
catch (FileNotFoundException e) {
  // deal with it. No really, deal with it!
  ... // this is me dealing with it
}

캐치 보이죠? 해당 API 메소드의 서명은 다음과 같습니다.

public FileInputStream(String name)
                throws FileNotFoundException

참고 FileNotFoundExceptionA는 확인 예외입니다.

API 프로그래머는 다음과 같이 말합니다. "이 생성자를 사용하여 새 FileInputStream을 만들 수 있지만

a) 파일 이름을 문자열로 전달 해야합니다.
b) 파일을 런타임에 찾지 못할 가능성을 수용 해야 합니다. "

그리고 그것이 내가 생각하는 한 요점입니다.

핵심은 기본적으로 질문이 "프로그래머의 통제를 벗어난 것들"이라고 말하는 것입니다. 저의 첫 생각은 API 프로그래머가 통제 할 수없는 것을 의미한다는 것입니다 . 그러나 실제로 올바르게 사용될 때 확인 된 예외는 실제로 클라이언트 프로그래머와 API 프로그래머가 제어하지 않는 것들에 대한 것이어야합니다. 이것이 이것이 확인 된 예외를 남용하지 않는 열쇠라고 생각합니다.

파일 열기가 그 요점을 잘 보여줍니다. API 프로그래머는 API를 호출 할 때 존재하지 않는 것으로 밝혀진 파일 이름을 제공 할 수 있으며 원하는 것을 반환 할 수는 없지만 예외를 throw해야한다는 것을 알고 있습니다. 또한이 문제는 정기적으로 발생하며 클라이언트 프로그래머는 호출 할 때 파일 이름이 정확할 것으로 예상 할 수 있지만 제어 할 수없는 이유로 인해 런타임에 잘못 될 수 있음을 알고 있습니다.

그래서 API는 그것을 명시 적으로 만듭니다 : 당신이 전화 할 때이 파일이 존재하지 않고 당신이 그것을 잘 다루는 경우가 있습니다.

이것은 카운터 케이스와 함께 더 명확합니다. 테이블 API를 작성한다고 상상해보십시오. 이 방법을 포함하여 API가있는 테이블 모델이 있습니다.

public RowData getRowData(int row) 

API 프로그래머로서 일부 클라이언트가 테이블 외부의 행 또는 행 값에 대해 음수 값을 전달하는 경우가 있음을 알고 있습니다. 따라서 확인 된 예외를 던져서 클라이언트가 처리하도록 유혹 할 수 있습니다.

public RowData getRowData(int row) throws CheckedInvalidRowNumberException

(물론 "체크 됨"이라고 부르지는 않습니다.)

이것은 확인 된 예외를 잘못 사용하는 것입니다. 클라이언트 코드는 행 데이터를 가져 오기위한 호출로 가득 차 있습니다. 모두 시도 / 캐치를 사용해야하며 무엇을해야합니까? 잘못된 행을 찾았다 고 사용자에게보고합니까? 아마도 아닙니다-테이블 뷰를 둘러싼 UI가 무엇이든, 사용자가 불법 행이 요청되는 상태가되도록해서는 안됩니다. 그래서 그것은 클라이언트 프로그래머의 버그입니다.

API 프로그래머는 여전히 클라이언트가 이러한 버그를 코딩 할 것으로 예상하고와 같은 런타임 예외로 처리해야합니다 IllegalArgumentException.

에서 예외를 확인하면 getRowDataHejlsberg의 게으른 프로그래머가 단순히 빈 캐치를 추가하게되는 경우입니다. 이 경우 잘못된 행 값은 테스터 나 클라이언트 개발자에게조차 명확하지 않으며 대신 소스를 찾기 어려운 노크 오류가 발생합니다. 출시 후 Arianne 로켓이 폭발합니다.

문제가 있습니다. 확인 된 예외 FileNotFoundException는 클라이언트 프로그래머에게 가장 유용한 방법으로 API를 정의하는 API 프로그래머 도구 상자의 좋은 도구 일뿐 만 아니라 필수 도구 라고 말하고 있습니다. 그러나 CheckedInvalidRowNumberException큰 불편은 프로그래밍에 나쁜 영향을 미치므로 피해야합니다. 그러나 차이점을 말하는 방법.

나는 그것이 정확한 과학이 아니라고 생각하며 Hejlsberg의 주장에 어느 정도 근거하고 아마도 정당화 될 것으로 생각합니다. 그러나 나는 여기에 목욕물을 가지고 아기를 버리는 것이 기쁘지 않으므로 여기에서 규칙을 추출하여 좋은 예외를 나쁜 것과 구별 할 수있게하십시오.

  1. 고객의 통제 불능 또는 폐쇄 대 개방 :

    확인 된 예외는 오류 사례가 API 클라이언트 프로그래머 가 제어 할 수없는 경우에만 사용해야합니다 . 이것은 시스템의 개방 또는 폐쇄 와 관련이 있습니다. 클라이언트 프로그래머가 테이블 뷰 (폐쇄 된 시스템)에서 행을 추가하고 삭제하는 모든 버튼, 키보드 명령 등을 제어 할 수 있는 제한된 UI에서 데이터를 가져 오려고 시도하면 클라이언트 프로그래밍 버그입니다. 존재하지 않는 행. 임의의 수의 사용자 / 응용 프로그램이 파일을 추가 및 삭제할 수있는 파일 기반 운영 체제 (개방형 시스템)에서 클라이언트가 요청한 파일이 지식없이 삭제되었으므로 처리해야합니다. .

  2. 편재:

    클라이언트가 자주 수행하는 API 호출에는 확인 된 예외를 사용하지 않아야합니다. 나는 종종 클라이언트 코드의 많은 장소를 의미합니다. 따라서 클라이언트 코드는 동일한 파일을 많이 열려고하지 않지만 내 테이블보기는 RowData다른 방법에서 온통 얻을 수 있습니다. 특히, 나는 다음과 같은 많은 코드를 작성할 것입니다

    if (model.getRowData().getCell(0).isEmpty())

    그리고 매번 시도 / 잡기를 감싸는 것이 고통 스러울 것입니다.

  3. 사용자에게 알리기 :

    최종 사용자에게 유용한 오류 메시지가 표시 될 수있는 경우 확인 된 예외를 사용해야합니다. 이것이 "어떻게됩니까?" 위의 질문. 또한 항목 1과 관련이 있습니다. 클라이언트 API 시스템 외부에있는 파일로 인해 파일이 없을 수 있다고 예상 할 수 있으므로 사용자에게 다음과 같이 합리적으로 말할 수 있습니다.

    "Error: could not find the file 'goodluckfindingthisfile'"

    불법 행 번호는 내부 버그와 사용자의 결함으로 인해 발생했기 때문에 실제로 제공 할 수있는 유용한 정보는 없습니다. 앱에서 런타임 예외가 콘솔로 넘어 가지 않도록하면 아마도 다음과 같은 추악한 메시지가 나타납니다.

    "Internal error occured: IllegalArgumentException in ...."

    간단히 말해, 클라이언트 프로그래머가 사용자에게 도움이되는 방식으로 예외를 설명 할 수 없다고 생각되면 체크 된 예외를 사용하지 않아야합니다.

이것이 저의 규칙입니다. 다소 의욕이 있었고 예외는 의심의 여지가 없습니다 (원한다면 수정하십시오). 그러나 내 주요 주장은 FileNotFoundException확인 된 예외가 매개 변수 유형만큼 API 계약의 중요하고 유용한 경우와 같은 경우가 있다는 것 입니다. 따라서 오용 된 것만으로 그 사실을 배제해서는 안됩니다.

미안하지만, 이것을 너무 길고 와플하게 만들려는 것은 아닙니다. 두 가지 제안으로 마무리하겠습니다.

A : API 프로그래머 : 유용성을 유지하기 위해 점검 된 예외를 거의 사용하지 마십시오. 의심스러운 경우 검사되지 않은 예외를 사용하십시오.

B : 클라이언트 프로그래머 : 개발 초기에 랩핑 된 예외 (Google 예외)를 만드는 습관을들이십시오. JDK 1.4 이상에서는이를 RuntimeException위한 생성자를 제공 하지만 쉽게 직접 생성 할 수도 있습니다. 생성자는 다음과 같습니다.

public RuntimeException(Throwable cause)

그런 다음 체크 된 예외를 처리해야하고 게으른 느낌이 들거나 (예 : API 프로그래머가 체크 된 예외를 처음 사용하는 데 지나치게 열중했다고 생각하는 경우) 습관을 들이고 예외를 삼키지 말고 감싸십시오. 다시 던져.

try {
  overzealousAPI(thisArgumentWontWork);
}
catch (OverzealousCheckedException exception) {
  throw new RuntimeException(exception);  
}

이것을 IDE의 작은 코드 템플릿 중 하나에 넣고 게으른 느낌이들 때 사용하십시오. 이렇게하면 실제로 확인 된 예외를 처리 해야하는 경우 런타임에 문제를 본 후 다시 돌아와서 처리해야합니다. 저를 믿으십시오 (Anders Hejlsberg).

catch (Exception e) { /* TODO deal with this at some point (yeah right) */}

110
파일을 여는 것은 실제로 반 생산적인 예외를 확인하는 좋은 예입니다. 대부분의 경우 파일을 여는 코드는 예외에 대해 유용한 기능을 수행 할 수 없으므로 호출 스택에서 여러 계층으로 수행하는 것이 좋습니다. 확인 된 예외는 메소드 서명을 어지럽히 게하여 어쨌든 할 수있는 일을 할 수 있도록합니다-예외가 가장 적합한 곳에서 예외를 처리하십시오.
Michael Borgwardt

116
@Michael : 당신은 일반적으로 여러 수준 높은 이들 IO 예외를 처리 할 수 동의 -하지만 난 당신이 당신이 API 클라이언트로 그 부정 들리지 않는 다음을 예상 할 수 있습니다. 이러한 이유로 확인 된 예외가 적절하다고 생각합니다. 예, 각 메소드 업 콜 스택에서 "throws"를 선언해야하지만 이것이 혼란 스럽습니다. 메소드 서명에 유용한 선언 정보입니다. 내 저수준 방법이 누락 된 파일로 실행될 수 있지만 처리 방법은 사용자에게 맡겨집니다. 나는 잃을 것이없고, 깨끗하고 좋은 코드 만 얻을 수있을 것입니다
Rhubarb

23
@Rhubarb : +1, 매우 흥미로운 답변은 양쪽에 대한 논쟁을 보여줍니다. 큰. 마지막 주석 정보 : 특히 메서드를 따라 인터페이스를 구현하는 경우 호출 스택에서 각 메소드에 대해 throw를 선언하는 것이 항상 가능한 것은 아닙니다.
R. Martinho Fernandes

8
이것은 매우 강력한 주장이지만 일반적으로 동의하지만 일반적인 콜백과 같이 작동하지 않는 경우가 있습니다. 라이브러리에 사용자 정의 코드를 호출하는 라이브러리가있는 경우 해당 라이브러리에 대해 호출 된 사용자 코드에서 확인 된 예외를 사용자 코드에서 전파하는 방법이 없습니다 (자바에서 아는 것). 이 문제는 또한 적절한 제네릭 형식을 지원하지 않는 많은 정적으로 형식화 된 언어의 형식 시스템의 다른 부분으로 확장됩니다. 이 답변은 이것에 대한 언급 (그리고 아마도 대답)에 의해 향상 될 것입니다.
Mankarse

7
@Rhubarb가 잘못되었습니다. 확인 된 예외는 처리 할 수 ​​있고 처리해야하는 '우발 상황'에 대한 것이지만 항상 "늦게 던져서 늦게 잡으십시오"모범 사례와 호환되지 않습니다. 파일을 여는 것은 다루어 질 있는 엄선 된 예 입니다. 대부분의 IOException (예 : 바이트 쓰기), SQLException, RemoteException은 의미있는 방식으로 처리 할 수 ​​없습니다. 실패 또는 재 시도는 "비즈니스"또는 "요청"레벨이어야하며 Java 라이브러리에서 사용되는 확인 된 예외는이를 어렵게 만드는 실수입니다. literatejava.com/exceptions/…
토마스 W

184

확인 된 예외에 대한 것은 개념을 일반적으로 이해함으로써 실제로 예외가 아니라는 것입니다. 대신 API 대체 반환 값입니다.

예외에 대한 전체 아이디어는 콜 체인 아래로 발생하는 오류가 개입하여 코드에 대해 걱정할 필요없이 코드 어딘가에서 거품을 일으켜 처리 할 수 ​​있다는 것입니다. 반면, 확인 된 예외는 던지기와 포수 간의 모든 수준의 코드가 예외를 통과 할 수있는 모든 형태의 예외에 대해 알고 있음을 선언해야합니다. 확인 된 예외가 단순히 호출자가 확인 해야하는 특별한 반환 값 인 경우 실제로는 거의 다릅니다. 예 : [의사 코드] :

public [int or IOException] writeToStream(OutputStream stream) {
    [void or IOException] a= stream.write(mybytes);
    if (a instanceof IOException)
        return a;
    return mybytes.length;
}

Java는 대체 반환 값 또는 간단한 인라인 튜플을 반환 값으로 수행 할 수 없으므로 확인 된 예외는 합리적인 응답입니다.

문제는 표준 라이브러리의 큰 스 와이드를 포함하여 많은 코드가 여러 수준을 잘 잡을 수있는 예외적 인 상황에서 예외를 잘못 사용한다는 것입니다. IOException이 RuntimeException이 아닌 이유는 무엇입니까? 다른 모든 언어에서는 IO 예외가 발생하도록 할 수 있으며 처리 할 작업이 없으면 응용 프로그램이 중지되고 유용한 스택 추적을 볼 수 있습니다. 이것이 일어날 수있는 가장 좋은 일입니다.

예제에서 두 개의 메소드를 사용하여 전체 스트림 작성 프로세스에서 모든 IOException을 포착하고 프로세스를 중단하고 오류보고 코드로 이동하십시오. Java에서는 모든 호출 수준, 심지어 IO가없는 수준까지 'throws IOException'을 추가하지 않으면 그렇게 할 수 없습니다. 이러한 메소드는 예외 처리에 대해 알 필요가 없습니다. 서명에 예외를 추가 해야하는 경우 :

  1. 불필요하게 커플 링을 증가시킨다;
  2. 인터페이스 서명을 변경하기 매우 취약하게 만듭니다.
  3. 코드를 읽기 어렵게 만듭니다.
  4. 일반적인 프로그래머의 반응은 'throws Exception', 'catch (Exception e) {}'와 같은 끔찍한 일을하거나 RuntimeException (디버깅을 더 어렵게 함)에 모든 것을 감싸서 시스템을 물리 치는 것입니다.

그리고 다음과 같은 어리석은 라이브러리 예외가 많이 있습니다.

try {
    httpconn.setRequestMethod("POST");
} catch (ProtocolException e) {
    throw new CanNeverHappenException("oh dear!");
}

이렇게 우스꽝스러운 코드로 코드를 복잡하게 만들어야 할 때 실제로 이것이 단순한 API 디자인이 아니더라도 확인 된 예외가 많은 증오를받는 것은 놀라운 일이 아닙니다.

또 다른 특별한 나쁜 영향은 구성 요소 A가 일반 구성 요소 B에 콜백을 제공하는 제어의 반전에 있습니다. B에 의해 수정 된 콜백 인터페이스가 변경되기 때문입니다. A는 예외를 더 많이 처리하는 상용구 인 RuntimeException에 실제 예외를 랩핑하여 처리 할 수 ​​있습니다.

Java 및 표준 라이브러리에서 구현 된 확인 된 예외는 상용구, 상용구, 상용구를 의미합니다. 이미 장황한 언어에서는 이것이 승리가 아닙니다.


14
코드 예제에서 로그를 읽을 때 원래 원인을 찾을 수 있도록 예외를 연결하는 것이 가장 좋습니다. throw CanNeverHappenException (e);
Esko Luontola

5
동의하지 않습니다. 체크 여부에 관계없이 예외는 예외적 인 조건입니다. 예 : HTTP를 통해 객체를 검색하는 메소드 반환 값은 객체이거나 아무것도 아닙니다. 나빠질 수있는 모든 것이 예외적입니다. C에서와 같이 반환 값으로 처리하면 혼란스럽고 디자인이 잘못됩니다.
미스터 스미스

15
@ 미스터 : Java에서 구현 된 확인 된 예외는 실제로 C ++ 및 기타 Java 이전 언어에서 인식 할 수있는 전통적인 '예외'보다 C에서와 같은 반환 값과 유사하게 작동한다는 것입니다. 그리고 그 IMO는 실제로 혼란과 열악한 디자인으로 이어집니다.
bobince

9
표준 라이브러리가 확인 된 예외를 잘못 사용하면 혼란과 나쁜 잡기 행동에 확실히 추가된다는 데 동의하십시오. 그리고 종종 잘못된 문서에서 비롯됩니다. 예를 들어 "일부 I / O 오류가 발생할 때 IOException을 발생시키는 disconnect ()와 같은 분리 방법"이 있습니다. 글쎄, 나는 연결을 끊었다! 핸들이나 다른 리소스를 유출하고 있습니까? 다시 시도해야합니까? 그런 일이 일어 났는지 알지 못하면 , 내가 취해야 할 행동을 이끌어 낼 수 없으므로 그냥 삼켜야하는지, 다시 시도하거나 구제해야하는지 추측해야합니다.
charstar

14
"API 대체 리턴 값"에 +1 확인 된 예외를 보는 흥미로운 방법.
Zsolt Török

75

확인 된 예외에 대해 모든 (다수) 이유를 다시 해치지 않고 하나만 선택하겠습니다. 이 코드 블록을 작성한 횟수를 잃었습니다.

try {
  // do stuff
} catch (AnnoyingcheckedException e) {
  throw new RuntimeException(e);
}

99 %의 시간 동안 나는 그것에 대해 아무것도 할 수 없습니다. 마지막으로 블록은 필요한 정리 작업을 수행합니다.

나는 또한 이것을 본 횟수를 잃어 버렸다.

try {
  // do stuff
} catch (AnnoyingCheckedException e) {
  // do nothing
}

왜? 누군가가 그것을 다루어야하고 게으 르기 때문에. 틀렸어? 확실한. 그런가요? 물론. 이것이 검사되지 않은 예외 인 경우 어떻게됩니까? 앱이 방금 사망했을 것입니다 (예외를 삼키는 것이 좋습니다).

그리고 java.text.Format 처럼 예외를 흐름 제어의 형태로 사용하는 화려한 코드 가 있습니다. Bzzzt. 잘못된. "abc"를 양식의 숫자 필드에 넣는 사용자는 예외가 아닙니다.

좋아, 그게 세 가지 이유 인 것 같아.


4
그러나 예외가 올바르게 포착되면 사용자에게 알리고 다른 작업 (로그?)을 수행하고 제어 된 방식으로 응용 프로그램을 종료 할 수 있습니다. 일부 API 부분이 더 잘 설계 될 수 있다는 데 동의합니다. 그리고 게으른 프로그래머 이유 때문에, 나는 프로그래머로서 당신은 당신의 코드에 100 % 책임이 있다고 생각합니다.
Mister Smith

3
try-catch-rethrow를 사용하면 메시지를 지정할 수 있습니다. 일반적으로 메시지를 사용하여 상태 변수의 내용에 대한 정보를 추가합니다. IOException이 해당 파일의 absolutePathName ()을 추가하는 경우가 자주 있습니다.
Thorbjørn Ravn Andersen

15
Eclipse와 같은 IDE는 빈 캐치 블록을 본 횟수만큼 많은 비난을받는다고 생각합니다. 실제로 기본적으로 다시 던져야합니다.
artbristol

12
"내가 그것에 대해 아무것도 할 수없는 시간의 99 %"-잘못, 앱이 중단되는 대신 "서버에 연결할 수 없습니다"또는 "IO 장치가 실패했습니다"라는 메시지를 사용자에게 표시 할 수 있습니다. 약간의 네트워크 딸꾹질 때문에. 두 가지 예 모두 나쁜 프로그래머의 작품입니다. 나쁜 프로그래머를 공격하고 예외 자체를 확인하지 않아야합니다. 샐러드 드레싱으로 사용할 때 당뇨병에 도움이되지 않아 인슐린을 공격하는 것과 같습니다.
AxiomaticNexus 2016 년

2
@YasmaniLlanes 항상 이런 일을 할 수는 없습니다. 때로는 준수해야 할 인터페이스가 있습니다. 그리고 유지 관리 가능한 API를 설계 할 때는 특히 부작용이 발생하기 시작할 수 없기 때문에 특히 그렇습니다. 그것과 그것의 복잡성으로 인해 대규모로 당신을 심하게 물릴 것입니다. 그렇습니다. 99 %의 시간에 대해서는 할 일이 없습니다.
MasterMastic

50

나는 이것이 오래된 질문이라는 것을 알고 있지만 확인 된 예외로 레슬링을 보내고 있으며 추가 할 것이 있습니다. 그것의 길이 나를 용서 해주세요!

확인 된 예외를 가진 나의 주요 소고기는 다형성을 망치는 것입니다. 다형성 인터페이스로 멋지게 연주하는 것은 불가능합니다.

좋은 자바 List인터페이스를 가져 가라 . 우리는 ArrayListand 같은 일반적인 인 메모리 구현을 가지고 있습니다 LinkedList. 또한 AbstractList새로운 유형의 목록을 쉽게 디자인 할 수 있는 골격 클래스 가 있습니다. 읽기 전용 목록의 경우 두 가지 방법 만 구현하면됩니다 : size()get(int index).

이 예제 WidgetList클래스 Widget는 파일에서 유형이 아닌 고정 크기 객체를 읽습니다 .

class WidgetList extends AbstractList<Widget> {
    private static final int SIZE_OF_WIDGET = 100;
    private final RandomAccessFile file;

    public WidgetList(RandomAccessFile file) {
        this.file = file;
    }

    @Override
    public int size() {
        return (int)(file.length() / SIZE_OF_WIDGET);
    }

    @Override
    public Widget get(int index) {
        file.seek((long)index * SIZE_OF_WIDGET);
        byte[] data = new byte[SIZE_OF_WIDGET];
        file.read(data);
        return new Widget(data);
    }
}

익숙한 List인터페이스를 사용하여 위젯을 노출하면 자체 를 알 필요없이 항목을 검색 list.get(123)하거나 ( for (Widget w : list) ...) 목록을 반복 할 수 있습니다 ( ) WidgetList. 이 목록을 일반 목록을 사용하는 모든 표준 메소드에 전달하거나로 묶을 수 Collections.synchronizedList있습니다. 이 코드를 사용하는 코드는 "위젯"이 그 자리에서 만들어 졌는지, 어레이에서 가져 왔는지, 또는 파일이나 데이터베이스에서 읽거나 네트워크를 통해 읽거나 미래의 서브 스페이스 릴레이에서 읽거나 알 필요가 없습니다. List인터페이스가 올바르게 구현 되었으므로 여전히 올바르게 작동합니다 .

그렇지 않다는 것을 제외하고. 위의 클래스는 파일 액세스 메소드가 IOException"캐치 또는 지정"해야하는 확인 된 예외를 발생 시킬 수 있으므로 컴파일되지 않습니다 . 당신은 그것으로 던져 지정할 수 없습니다 - 즉 계약 위반 때문에 컴파일러가 당신을 못하게 List인터페이스를. 그리고 WidgetList나중에 설명 할 것처럼 자체적으로 예외를 처리 할 수있는 유용한 방법은 없습니다 .

분명히 할 일은 확인되지 않은 예외로 catch 된 예외를 catch하고 다시 던지는 것입니다.

@Override
public int size() {
    try {
        return (int)(file.length() / SIZE_OF_WIDGET);
    } catch (IOException e) {
        throw new WidgetListException(e);
    }
}

public static class WidgetListException extends RuntimeException {
    public WidgetListException(Throwable cause) {
        super(cause);
    }
}

((편집 : Java 8 UncheckedIOException은이 경우를 위해 클래스를 추가했습니다 IOException.

따라서 확인 된 예외 이와 같은 경우에는 작동하지 않습니다 . 당신은 그들을 던질 수 없습니다. Map데이터베이스에 의해 뒷받침되는 영리함을위한 Ditto 또는 java.util.RandomCOM 포트를 통해 양자 엔트로피 소스 에 연결된 구현 . 다형성 인터페이스의 구현으로 새로운 것을 시도하자마자 확인 된 예외 개념이 실패합니다. 그러나 확인 된 예외는 너무 교활하여 여전히 안전하지 않습니다. 낮은 수준의 메소드를 잡아서 다시 던져서 코드를 어수선하게하고 스택 추적을 어수선하게해야하기 때문입니다.

유비쿼터스 Runnable인터페이스가 확인 된 예외를 던지는 무언가를 호출하면 종종이 코너로 돌아갑니다. 그대로 예외를 던질 수 없으므로 할 수있는 모든 것은 코드를 잡아서 다시 던져서 코드를 어지럽히는 것 RuntimeException입니다.

실제로 해킹에 의존하면 선언되지 않은 확인 된 예외를 던질 수 있습니다 . 런타임시 JVM은 확인 된 예외 규칙을 신경 쓰지 않으므로 컴파일러 만 바보로 만들어야합니다. 가장 쉬운 방법은 제네릭을 남용하는 것입니다. 이것은 내 메소드입니다 (Java 8 이전에 일반 메소드의 호출 구문에 필요하기 때문에 클래스 이름이 표시됨).

class Util {
    /**
     * Throws any {@link Throwable} without needing to declare it in the
     * method's {@code throws} clause.
     * 
     * <p>When calling, it is suggested to prepend this method by the
     * {@code throw} keyword. This tells the compiler about the control flow,
     * about reachable and unreachable code. (For example, you don't need to
     * specify a method return value when throwing an exception.) To support
     * this, this method has a return type of {@link RuntimeException},
     * although it never returns anything.
     * 
     * @param t the {@code Throwable} to throw
     * @return nothing; this method never returns normally
     * @throws Throwable that was provided to the method
     * @throws NullPointerException if {@code t} is {@code null}
     */
    public static RuntimeException sneakyThrow(Throwable t) {
        return Util.<RuntimeException>sneakyThrow1(t);
    }

    @SuppressWarnings("unchecked")
    private static <T extends Throwable> RuntimeException sneakyThrow1(
            Throwable t) throws T {
        throw (T)t;
    }
}

만세! 이것을 사용하여 선언하지 않고 스택에 깊이를 검사 RuntimeException하지 않고 스택 추적 을 래핑 하지 않고 스택 추적을 혼란스럽게 만들 수 있습니다! "WidgetList"예제를 다시 사용하여 :

@Override
public int size() {
    try {
        return (int)(file.length() / SIZE_OF_WIDGET);
    } catch (IOException e) {
        throw sneakyThrow(e);
    }
}

불행히도, 점검 된 예외의 최종 모욕은 컴파일러 가 결함이 있다고 판단 할 수없는 경우 점검 된 예외 를 잡을 수 없도록 거부한다는 것 입니다. (체크되지 않은 예외에는이 규칙이 없습니다.) 교묘하게 던져진 예외를 포착하려면 다음을 수행해야합니다.

try {
    ...
} catch (Throwable t) { // catch everything
    if (t instanceof IOException) {
        // handle it
        ...
    } else {
        // didn't want to catch this one; let it go
        throw t;
    }
}

다소 어색하지만 플러스 측면에서는에 싸여있는 확인 된 예외를 추출하는 코드보다 약간 간단합니다 RuntimeException.

유감스럽게도, 예외를 다시 던지는 것에 대해 Java 7에 추가 된 규칙 덕분에 throw t;유형 t이 확인 되었지만 여기에서 합법적 입니다.


확인 된 예외가 다형성을 충족하면 반대의 경우도 문제가됩니다. 메소드가 잠재적으로 확인 된 예외를 throw하는 것으로 지정되었지만 재정의 된 구현은 그렇지 않습니다. 예를 들어, 추상 클래스 OutputStreamwrite메소드는 모두 지정 throws IOException합니다. ByteArrayOutputStream실제 I / O 소스 대신 메모리 내 배열에 쓰는 서브 클래스입니다. 재정의 된 write메소드는 IOExceptions를 유발할 수 없으므로 throws절이 없으므로 catch-or-specify 요구 사항에 대한 걱정없이 호출 할 수 있습니다.

항상 그렇지는 않습니다. Widget스트림에 저장하는 방법이 있다고 가정하십시오 .

public void writeTo(OutputStream out) throws IOException;

이 방법으로 평범한 것을 받아들이 OutputStream는 것이 옳은 일이므로 파일, 데이터베이스, 네트워크 등 모든 종류의 출력에 다형성으로 사용할 수 있습니다. 그리고 메모리 내 배열. 그러나 메모리 내 배열을 사용하면 실제로 발생할 수없는 예외를 처리해야하는 가짜 요구 사항이 있습니다.

ByteArrayOutputStream out = new ByteArrayOutputStream();
try {
    someWidget.writeTo(out);
} catch (IOException e) {
    // can't happen (although we shouldn't ignore it if it does)
    throw new RuntimeException(e);
}

평소와 같이 확인 된 예외가 발생합니다. 변수가 개방형 예외 요구 사항이 더 많은 기본 유형으로 선언 된 경우 응용 프로그램에서 해당 예외 가 발생하지 않는다는 것을 알고 있더라도 해당 예외에 대한 처리기를 추가 해야합니다.

그러나 확인 된 예외는 실제로 너무 성가 시므로 반대의 경우도 마찬가지입니다! 현재 에 대한 호출에서 IOException발생하는 모든 것을 포착한다고 가정 하지만 변수의 선언 유형을 a로 변경 하려고하면 컴파일러는 throw 할 수 없다고 확인 된 예외를 잡으려고 시도하면 요금을 청구합니다.writeOutputStreamByteArrayOutputStream

이 규칙은 일부 터무니없는 문제를 일으 킵니다. 예를 들어, 세 가지 중 하나 write의 방법 OutputStream입니다 하지 에 의해 오버라이드 (override) ByteArrayOutputStream. 특히 오프셋 0과 배열 길이 write(byte[] data)로 호출하여 전체 배열을 작성하는 편리한 방법입니다 write(byte[] data, int offset, int length). ByteArrayOutputStream3 인수 메서드를 재정의하지만 1 인수 편의 메서드를 그대로 상속합니다. 상속 된 메소드는 옳은 일을하지만 원치 않는 throws절을 포함합니다 . 그것은 아마도의 디자인에 대한 감독일지도 ByteArrayOutputStream모르지만 예외를 잡는 코드와의 소스 호환성을 깨뜨릴 수 있기 때문에 그것을 고칠 수는 없습니다. 예외는 결코, 결코, 결코 던져지지 않을 것입니다!

그 규칙은 편집과 디버깅 중에도 성가시다. 예를 들어, 때로는 메소드 호출을 일시적으로 주석 처리하고 확인 된 예외가 발생했을 경우 컴파일러는 이제 로컬 trycatch블록 의 존재에 대해 불평 합니다. 그래서 나도 그 주석해야하고, 내 코드를 편집 할 때 때문에 이제 IDE가 잘못된 수준으로 들여 쓰기합니다 {및이 }주석하고 있습니다. 가! 작은 불만이지만 확인 된 예외를 확인하는 유일한 방법은 문제를 일으키는 것 같습니다.


거의 다 했어요. 확인 된 예외에 대한 나의 마지막 좌절 은 대부분의 콜 사이트 에서 그들과 함께 할 수있는 유용한 것이 없다는 것입니다. 이상적으로 문제가 발생하면 사용자에게 문제를 알리거나 작업을 적절하게 종료하거나 다시 시도 할 수있는 유능한 응용 프로그램 별 처리기가 있습니다. 전체 목표를 아는 유일한 사람이기 때문에 스택을 높은 처리기만이 작업을 수행 할 수 있습니다.

대신 우리는 다음 관용구를 얻습니다.이 관용구는 컴파일러를 종료하는 방법으로 만연합니다.

try {
    ...
} catch (SomeStupidExceptionOmgWhoCares e) {
    e.printStackTrace();
}

GUI 또는 자동 프로그램에서 인쇄 된 메시지가 표시되지 않습니다. 더 나쁜 것은 예외 후에 나머지 코드로 진행됩니다. 예외는 실제로 오류가 아닌가? 그런 다음 인쇄하지 마십시오. 그렇지 않으면 다른 예외가 순간적으로 날아가고 그 시간까지 원래 예외 객체가 사라집니다. 이 관용구는 BASIC On Error Resume Next이나 PHP 보다 낫지 않습니다 error_reporting(0);.

어떤 종류의 로거 클래스를 호출하는 것은 그리 좋지 않습니다.

try {
    ...
} catch (SomethingWeird e) {
    logger.log(e);
}

그것은 e.printStackTrace();불확실한 상태의 코드와 마찬가지로 게으 르며 여전히 쟁기질입니다. 또한 특정 로깅 시스템 또는 다른 처리기의 선택은 응용 프로그램에 따라 다르므로 코드 재사용이 손상됩니다.

하지만 기다려! 응용 프로그램 별 처리기를 찾는 가장 쉽고 보편적 인 방법이 있습니다. 호출 스택보다 높거나 Thread의 catch되지 않은 예외 처리기 로 설정되어 있습니다. 따라서 대부분의 장소 에서 예외를 스택 위로 던지기 만하면 됩니다. 예, throw e;. 확인 된 예외는 방해가됩니다.

나는 언어가 디자인되었을 때 확인 된 예외가 좋은 생각처럼 들릴 것이라고 확신하지만 실제로는 그것들이 모두 귀찮고 아무런 이점이 없다는 것을 알았습니다.


WidgetList를 사용하여 size 메서드의 경우 크기를 변수에 캐시하고 생성자에서 설정합니다. 생성자는 예외를 자유롭게 던질 수 있습니다. 그래도 WidgetList를 사용하는 동안 파일이 변경되면 작동하지 않을 것입니다.
TofuBeer

2
누군가는 그것을 던질만큼 충분히 배려했습니다. 따라서 절대로 던져지지 않았거나 (나쁜 디자인) 실제로 처리해야합니다. 불행히도 디자인이 좋지 않은 1.0 이전 클래스 (바이트 배열 출력 스트림)의 잘못된 구현에 대해서도 마찬가지입니다.
TofuBeer

2
적절한 관용구는 중첩 된 서브 루틴 호출에 의해 발생 된 지정된 예외를 포착하고이를에 다시 던져 넣는 지시문 일 것 RuntimeException입니다. 루틴은 동시에 선언 될 수 있으며 중첩 된 호출에서 발생 된 throws IOException모든 항목이 IOException예상치 못한 랩으로 간주되도록 지정할 수 있습니다.
supercat

15
나는이 게시물을 우연히 발견 한 Java 경험을 가진 전문 C # 개발자입니다. 나는 왜 누군가가이 기괴한 행동을지지 할 것인지에 대해 당황했습니다. .NET에서 특정 유형의 예외를 잡으려는 경우 잡을 수 있습니다. 스택에 버리려면 할 일이 없습니다. Java가 그렇게 기발하지 않았기를 바랍니다. :)
aikeru

"때로는 메소드 호출을 일시적으로 주석 처리 할 것"에 관해-나는 if (false)이것을 사용 하는 법을 배웠다 . throw 절 문제를 피하고 경고를 통해 더 빨리 탐색 할 수 있습니다. +++ 그것은 당신이 쓴 모든 것에 동의합니다. 확인 된 예외에는 값이 있지만 비용과 비교할 때이 값은 무시할 수 있습니다. 거의 항상 그들은 방해가됩니다.
maaartinus

45

글쎄, 그것은 스택 트레이스를 표시하거나 자동으로 충돌하는 것이 아닙니다. 계층 간 오류를 전달할 수 있다는 것입니다.

확인 된 예외의 문제는 사람들이 중요한 세부 사항 (즉, 예외 클래스)을 삼키도록 권장한다는 것입니다. 그 세부 사항을 삼키지 않기로 선택한 경우 전체 앱에서 던지기 선언을 계속 추가해야합니다. 이는 1) 새로운 예외 유형이 많은 함수 시그니처에 영향을 미치며, 2) 실제로 포착하려는 예외의 특정 인스턴스를 놓칠 수 있음을 의미합니다 (예 : 데이터를 보조 파일은 선택 사항이므로 오류를 무시할 수 있지만 서명 throws IOException이므로이를 간과하기 쉽습니다).

실제로 응용 프로그램 에서이 상황을 처리하고 있습니다. 거의 예외를 AppSpecificException으로 다시 패키지했습니다. 이로 인해 서명이 정말 깨끗해졌으며 서명 폭발 throws에 대해 걱정할 필요가 없었습니다 .

물론, 이제 재시도 로직 등을 구현하여 더 높은 수준의 오류 처리를 전문화해야합니다. 그러나 모든 것은 AppSpecificException이므로 "IOException이 발생하면 다시 시도하십시오"또는 "ClassNotFound가 발생하면 완전히 중단하십시오"라고 말할 수 없습니다. 우리는 코드와 타사 코드 사이를 통과하면서 물건이 계속해서 다시 포장되기 때문에 실제 예외에 도달 하는 신뢰할 수있는 방법이 없습니다 .

이것이 내가 파이썬에서 예외 처리를 좋아하는 이유입니다. 당신이 원하는 것 그리고 / 또는 처리 할 수있는 것만 잡을 수 있습니다. 마치 자신을 다시 던지는 것처럼 다른 모든 것이 버블 링됩니다 (어쨌든 수행 한 것).

필자는 몇 번이고 여러 번 발견했으며 언급 한 프로젝트 전체에서 예외 처리는 3 가지 범주로 나뉩니다.

  1. 특정 예외를 포착하고 처리하십시오 . 예를 들어, 이것은 재시도 로직을 구현하기위한 것입니다.
  2. 다른 예외를 잡아서 다시 던지십시오 . 여기서 일어나는 모든 일은 보통 로깅이며, "$ filename을 열 수 없습니다"와 같은 간단한 메시지입니다. 이것들은 당신이 할 수없는 오류입니다. 더 높은 레벨 만 처리 할 수 ​​있습니다.
  3. 모든 것을 잡아서 오류 메시지를 표시합니다. 이것은 일반적으로 디스패처의 루트에 있으며 예외가 아닌 메커니즘 (팝업 대화 상자, RPC 오류 객체 마샬링 등)을 통해 호출자에게 오류를 전달할 수 있도록합니다.

5
일반 메소드 서명을 유지하면서 분리를 허용하기 위해 AppSpecificException의 특정 서브 클래스를 작성할 수 있습니다.
Thorbjørn Ravn Andersen

1
또한 항목 2에 매우 중요한 추가 사항은 예외 예외에 정보를 추가 할 수 있다는 것입니다 (예 : RuntimeException에 중첩하여). 로그 파일에 숨겨져있는 것보다 스택 추적에없는 파일 이름을 갖는 것이 훨씬 좋습니다.
Thorbjørn Ravn Andersen

1
기본적으로 귀하의 주장은 "예외 관리가 지치므로 처리하지 않겠습니다"입니다. 예외가 발생하면 의미가 떨어지고 컨텍스트 작성은 사실상 쓸모가 없습니다. API 디자이너가 문제가 발생했을 때 예상 할 수있는 사항에 대해 계약 상 명확하게 알 수 있습니다. 프로그램 또는 예외가 발생했을 때이 예외 또는 예외가 "버블 업"될 수 있다는 알림을받지 못했을 경우 고장의 결과 내 시스템이 가능한 한 안정적이지 않습니다.
Newtopian 2009

4
그것은 내가 전혀 말하는 것이 아닙니다. 마지막 문장이 실제로 저에게 동의합니다. 모든 것이 AppSpecificException에 싸여 있으면 버블 링되지 않고 의미 / 컨텍스트가 손실됩니다. 그렇습니다 .API 클라이언트에 알리지 않습니다. 이것은 Java에서와 같이 확인 된 예외로 정확히 발생합니다. 사람들은 많은 throws선언 으로 함수를 다루기를 원하지 않기 때문 입니다.
Richard Levasseur

6
@Newtopian-예외는 "비즈니스"또는 "요청"수준에서만 처리 할 수 ​​있습니다. 모든 작은 잠재적 인 실패가 아니라 큰 단위로 실패하거나 재 시도하는 것이 합리적입니다. 이러한 이유로 예외 처리 모범 사례는 "초기 던져, 늦게 잡아라"로 요약됩니다. 확인 된 예외로 인해 올바른 수준에서 안정성을 관리 하기어려워지고 잘못 코딩 된 많은 catch 블록이 권장됩니다. literatejava.com/exceptions/…
토마스 W

24

SNR

먼저, 확인 된 예외는 코드의 "신호 대 잡음비"를 감소시킵니다. Anders Hejlsberg도 비슷한 개념 인 명령형 대 선언 형 프로그래밍에 대해 설명합니다. 어쨌든 다음 코드 스 니펫을 고려하십시오.

Java에서 비 UI 스레드에서 UI를 업데이트하십시오.

try {  
    // Run the update code on the Swing thread  
    SwingUtilities.invokeAndWait(() -> {  
        try {
            // Update UI value from the file system data  
            FileUtility f = new FileUtility();  
            uiComponent.setValue(f.readSomething());
        } catch (IOException e) {  
            throw new UncheckedIOException(e);
        }
    });
} catch (InterruptedException ex) {  
    throw new IllegalStateException("Interrupted updating UI", ex);  
} catch (InvocationTargetException ex) {
    throw new IllegalStateException("Invocation target exception updating UI", ex);
}

C #에서 UI가 아닌 스레드에서 UI를 업데이트하십시오.

private void UpdateValue()  
{  
   // Ensure the update happens on the UI thread  
   if (InvokeRequired)  
   {  
       Invoke(new MethodInvoker(UpdateValue));  
   }  
   else  
   {  
       // Update UI value from the file system data  
       FileUtility f = new FileUtility();  
       uiComponent.Value = f.ReadSomething();  
   }  
}  

나에게 훨씬 더 분명한 것 같습니다. Swing에서 점점 더 많은 UI 작업을 시작하면 확인 된 예외가 실제로 성 가시고 쓸모 없게됩니다.

감옥 휴식

Java의 List 인터페이스와 같은 가장 기본적인 구현을 구현하기 위해 계약에 의한 설계 도구로 예외를 확인했습니다. 데이터베이스 나 파일 시스템 또는 점검 된 예외를 발생시키는 다른 구현으로 지원되는 목록을 고려하십시오. 유일하게 가능한 구현은 확인 된 예외를 잡아서 확인되지 않은 예외로 다시 던지는 것입니다.

@Override
public void clear()  
{  
   try  
   {  
       backingImplementation.clear();  
   }  
   catch (CheckedBackingImplException ex)  
   {  
       throw new IllegalStateException("Error clearing underlying list.", ex);  
   }  
}  

이제 모든 코드의 요점이 무엇인지 물어봐야합니다. 확인 된 예외는 소음을 추가하고 예외는 포착되었지만 처리되지 않았으며 계약에 의한 설계 (확인 된 예외 측면에서)가 고장났습니다.

결론

  • 예외 포착은 처리와 다릅니다.
  • 확인 된 예외는 코드에 노이즈를 추가합니다.
  • 예외 처리는 C #에서 잘 처리됩니다.

나는 이것 대해 이전에 블로그했다 .


3
이 예에서 Java와 C #은 예외를 처리하지 않고 전파합니다 (IllegalStateException을 통한 Java). 차이점은 FileNotFoundException을 처리하려고하지만 InvocationTargetException 또는 InterruptedException을 처리하는 것이 유용하지 않을 것입니다.
Luke Quinane 2009

3
그리고 C # 방식으로 I / O 예외가 발생할 수 있음을 어떻게 알 수 있습니까? 또한 나는 실행에서 예외를 던지지 않을 것입니다 ... 나는 학대 예외 처리를 고려합니다. 죄송하지만 코드의 해당 부분에 대해서는 아직 귀하의 측면을 볼 수 있습니다.
TofuBeer

7
우리는 거기에 도착하고 있습니다 :-) 그래서 API의 새로운 릴리스마다 모든 호출을 빗겨 서 발생할 수있는 새로운 예외를 찾아야합니까? 이전 버전과의 호환성에 대해 걱정할 필요가 없으므로 회사 API 내부에서 쉽게 발생할 수 있습니다.
TofuBeer

3
신호 대 잡음비를 낮추는 것을 의미 했습니까 ?
neo2862

3
@TofuBeer 기본 API의 인터페이스가 좋은 것으로 바뀌면 코드를 업데이트하지 않습니까? 확인되지 않은 예외 만 있었다면, 알지 못하고 깨지거나 불완전한 프로그램이 생겼을 것입니다.
Francois Bourgeois

23

Artima 는 .NET의 건축가 중 한 명인 Anders Hejlsberg 와의 인터뷰를 통해 확인 된 예외에 대한 주장을 심각하게 다루고 있습니다. 짧은 맛보는 사람 :

throws 절은 적어도 Java로 구현되는 방식으로 예외를 처리하도록 강제하지는 않지만 예외를 처리하지 않으면 예외를 통과 할 수있는 정확한 예외를 인정해야합니다. 선언 된 예외를 잡아 내거나 자신의 throws 절에 넣어야합니다. 이 요구 사항을 해결하기 위해 사람들은 우스운 일을합니다. 예를 들어, 그들은 "예외를 던지다"라고 모든 방법을 장식합니다. 그것은 그 기능을 완전히 무너 뜨리고, 프로그래머가 좀 더 거친 글을 쓰도록 만들었습니다. 그것은 아무도 도움이되지 않습니다.


2
사실, 수석 건축가.
Trap

18
나는 그의 주장이 "나쁜 프로그래머가있다"고 결론을 내렸다.
TofuBeer

6
두부 맥주 요점은 호출 된 메소드가 던지는 예외와 관련하여 여러 번 알지 못하며 실제로 관심이있는 사례는 언급되지 않았다는 것입니다. 예를 들어 파일을 열면 IO 예외가 발생합니다. 예를 들어 내 문제가 아니므로 버립니다. 그러나 최상위 호출 방법은 처리를 중지하고 알 수없는 문제가 있음을 사용자에게 알리려고합니다. 확인 된 예외는 전혀 도움이되지 않았습니다. 일어날 수있는 백만 가지 이상한 일 중 하나였습니다.
Dan Rosenstark

4
@yar, 확인 된 예외가 마음에 들지 않으면 "새로운 RuntimeException 던지기 ("Foo.bar ()를 수행 할 때 이것을 기대하지 않았습니다. ", e)")하고 완료하십시오.
Thorbjørn Ravn Andersen

4
@ ThorbjørnRavnAndersen : 불행히도 .net을 복사 한 Java의 기본 디자인 약점은 예외 유형을 사용 여부를 결정하는 기본 수단과 일반적인 유형을 나타내는 기본 수단으로 사용한다는 것입니다 사실 두 문제가 대체로 직교 할 때 잘못되었습니다. 중요한 것은 잘못 된 것이 아니라 상태 객체가있는 것입니다. 또한 .net과 Java는 기본적으로 예외에 대한 조치와 해결은 일반적으로 종종 다르면 일반적으로 동일한 것으로 가정합니다.
supercat

20

나는 항상 확인 된 예외를 선호했기 때문에 처음에 당신과 동의했으며 .Net에서 예외를 확인하지 않은 이유에 대해 생각하기 시작했습니다. 그러나 나는 확인 된 예외와 같은 사실이 아니라는 것을 깨달았습니다.

당신의 질문에 대답하기 위해, 예, 나는 내 프로그램이 스택 추적, 바람직하게는 정말로 추악한 것을 보여주기를 좋아합니다. 응용 프로그램을보고 싶었던 가장 추악한 오류 메시지의 힙으로 폭발하기를 원합니다.

그리고 그 이유는 그렇게한다면 문제를 해결해야하고 바로 고쳐야하기 때문입니다. 문제가 있음을 즉시 알고 싶습니다.

실제로 몇 번이나 예외를 처리합니까? 예외를 잡는 것에 대해 말하는 것이 아니라 예외를 다루는 것에 대해 말하는 것입니까? 다음을 작성하는 것이 너무 쉽습니다.

try {
  thirdPartyMethod();
} catch(TPException e) {
  // this should never happen
}

그리고 당신이 나쁜 습관이라고 말할 수 있다는 것을 알고 있습니다. '답변'은 예외로 무언가를하는 것입니다. 그것.

그렇습니다. 그렇지 않으면 예외를 포착하고 싶지 않습니다. 나를 조일 때 프로그램이 크게 폭발하기를 원합니다. 조용히 실패하는 것이 최악의 결과입니다.


Java는 이러한 종류의 작업을 수행하도록 권장하므로 모든 메소드 서명에 모든 유형의 예외를 추가하지 않아도됩니다.
yfeldblum

17
Funny .. 확인 된 예외를 올바르게 받아 들여서 적절하게 사용한 이래로 내 프로그램은 고객의 불만에 시달리는 거대한 더미에서 폭발을 멈추었습니다. 개발하는 동안 스택 추적에 큰 못생긴 스택 추적이있는 경우 고객도 가져옵니다. DX는 XYZ 버튼의 색상 구성을 파싱 할 수 없다는 작은 트레이 알림 대신 충돌 한 시스템에서 1 마일 높은 스택 추적으로 ArrayIndexOutOfBoundsException을 볼 때 얼굴을 보았습니다. 따라
Newtopian

1
아마도 Java가 필요로하는 것은 "cantHandle"선언 일 것인데, 이것은 코드 나 메소드가 코드 내에서 발생하는 특정 예외를 처리 할 준비가되지 않았으며 명시 적 이외의 다른 방법을 통해 발생하는 예외를 처리하도록 지정합니다. 호출 된 메소드와 달리 해당 메소드 내에서 throw는 자동으로 래핑되고 RuntimeException에서 다시 발생해야합니다. IMHO, 확인 된 예외는 랩되지 않고 호출 스택을 거의 전파 하지 않아야합니다 .
supercat

3
@Newtopian-저는 서버 및 고 신뢰성 소프트웨어를 작성하고 25 년 동안 그렇게 해왔습니다. 저의 프로그램은 결코 폭파 되지 않았 으며, 고 가용성, 재시도 및 재 연결, 통합 기반 금융 및 군사 시스템과 협력하고 있습니다. 런타임 예외를 선호하는 절대 객관적인 기초가 있습니다. 확인 된 예외는 올바른 "초기 던져, 늦게 잡기"모범 사례를 따르는 것이 더 어렵습니다. 올바른 안정성 및 오류 처리는 "비즈니스", "연결"또는 "요청"수준입니다. (또는 때때로 데이터를 구문 분석 할 때). 확인 된 예외는 올바르게 수행하는 데 방해가됩니다.
Thomas W

1
여기서 이야기하는 예외는 RuntimeExceptions실제로 잡을 필요가 없으며 프로그램을 시작해야한다는 데 동의합니다. 항상 파악하고 처리해야하는 예외는 다음과 같은 확인 된 예외 IOException입니다. 를 얻는다면 IOException코드에서 고칠 것이 없습니다. 네트워크 문제가 발생하여 프로그램이 중단되지 않아야합니다.
AxiomaticNexus 2016 년

20

Effective Java Exceptions 기사 는 체크되지 않은 상태를 사용하는시기와 체크 된 예외를 사용하는시기를 잘 설명합니다. 주요 기사를 강조하기 위해이 기사에서 인용 한 내용은 다음과 같습니다.

우발성 : 방법의 의도 된 목적으로 표현 될 수있는 방법으로부터 대안적인 반응을 요구하는 예상 조건. 이 방법의 호출자는 이러한 종류의 조건을 예상하고 이에 대처하기위한 전략을 가지고 있습니다.

결함 : 메소드의 내부 구현을 참조하지 않고 설명 할 수없는 의도 된 목적을 달성 할 수없는 계획되지 않은 조건.

(SO는 테이블을 허용하지 않으므로 원본 페이지 에서 다음을 읽을 수 있습니다 ...)

우연성

  • 다음으로 간주됩니다 : 디자인의 일부
  • 일어날 것으로 예상됩니다 : 정기적이지만 드물게
  • 누가 신경 쓰는지 : 메소드를 호출하는 업스트림 코드
  • 예 : 대체 리턴 모드
  • 최상의 매핑 : 확인 된 예외

결점

  • 다음과 같이 간주됩니다 :
  • 일어날 것으로 예상됩니다 : 절대
  • 누가 신경 쓰는가 : 문제를 해결해야하는 사람들
  • 예 : 프로그래밍 버그, 하드웨어 오작동, 구성 실수, 파일 누락, 사용할 수없는 서버
  • 최상의 매핑 : 확인되지 않은 예외

나는 그것들을 언제 사용해야하는지 알고, 왜 그 조언을 따르지 않는 사람들이 그 조언을 따르지 않는지 알고 싶다 :-)
TofuBeer

프로그래밍 버그 란 무엇이며 사용법 버그 와 구별하는 방법 은 무엇입니까 ? 사용자가 프로그램에 잘못된 인수를 전달하면 프로그래밍 버그입니까? Java 관점에서는 프로그래밍 버그가 아닐 수 있지만 쉘 스크립트 관점에서는 프로그래밍 버그입니다. 따라서 잘못된 인수는 args[]무엇입니까? 그것들은 우발입니까 아니면 결함입니까?
ceving

3
@TofuBeer-Java 라이브러리 디자이너이기 때문에 모든 종류의 복구 할 수없는 저수준 오류를 명확하게 선택 해제 해야 할 때 확인 된 예외 로 설정했습니다 . 예를 들어 FileNotFound는 확인해야 할 유일한 IOException입니다. JDBC와 관련하여 데이터베이스에만 연결하는 것은 합리적으로 우발적 인 것으로 간주 될 수 있습니다 . 다른 모든 SQLException은 실패 했으며 선택 취소 해야합니다 . 오류 처리는 "비즈니스"또는 "요청"수준에 정확하게 있어야합니다. "초기 던지기, 늦게 잡기"모범 사례를 참조하십시오. 확인 된 예외는 그에 대한 장벽입니다.
Thomas W

1
당신의 주장에는 하나의 커다란 결함이 있습니다. "우발성"은 예외를 통해 처리되지 말고 비즈니스 코드 및 메소드 리턴 값을 통해 처리해야합니다. 예외적으로 예외적 인 상황, 즉 결함이 있습니다.
Matteo Mosca

@MatteoMosca 오류 리턴 코드는 무시되는 경향이 있으므로 해당 코드를 실격 처리하기에 충분합니다. 실제로, 비정상적인 것은 종종 스택의 어딘가에서 처리 될 수 있으며 예외의 유스 케이스입니다. File#openInputStream돌아 오는 것과 같은 것을 상상할 Either<InputStream, Problem>수 있습니다. 그것이 당신이 의미하는 바라면 우리는 동의 할 것입니다.
maaartinus

19

한마디로 :

API 디자인 문제는 예외입니다. -- 그 이상도 이하도 아닌.

확인 된 예외에 대한 인수 :

확인 된 예외가 좋지 않은 이유를 이해하려면 다음과 같이 질문을하고 질문하십시오. 확인 된 예외가 언제 또는 왜 매력적인 지, 즉 컴파일러가 예외 선언을 시행하도록하려는 이유는 무엇입니까?

때로는 : 대답은 분명 필요 예외를 잡으려고하고, 코드에 관심이있는 오류에 대한 특정 예외 클래스 이벤트를 호출되는 경우 그에만 가능합니다.

따라서, 인수 에 대한 확인 예외는 컴파일러 힘 프로그래머는 예외가 슬로우되는 선언하고 있다는 것입니다 희망 프로그래머 것이다 다음 문서 특정 예외 클래스와 그 원인 오류도.

그러나 실제로는 종종 패키지 가 특정 서브 클래스 com.acmeAcmeException아닌 던지기만을 던집니다 . 그런 다음 발신자는 처리, 선언 또는 재 신호 AcmeExceptions를 보내야하지만 AcmeFileNotFoundError상황이 발생했는지 또는 확실하지 않을 수 있습니다 AcmePermissionDeniedError.

따라서에 관심이있는 AcmeFileNotFoundError경우 솔루션은 ACME 프로그래머에게 기능 요청을 제출하고 해당 서브 클래스를 구현, 선언 및 문서화하도록 지시하는 것입니다 AcmeException.

왜 귀찮게?

따라서 확인 된 예외가 있더라도 컴파일러는 프로그래머가 유용한 예외 를 처리하도록 강제 할 수 없습니다 . 여전히 API 품질의 문제입니다.

결과적으로 확인 된 예외가없는 언어는 대개 더 나 빠지지 않습니다. 프로그래머가 Error아닌 일반 클래스 의 비 특정 인스턴스를 던지려고 할 수도 AcmeException있지만 API 품질에 관심이 있다면 AcmeFileNotFoundError결국 소개하는 법을 배우게됩니다 .

전반적으로 예외의 사양 및 문서는 일반적인 방법의 사양 및 문서와 크게 다르지 않습니다. 이것도 API 디자인 문제이며 프로그래머가 유용한 기능을 구현하거나 내보내는 것을 잊어 버린 경우 API를 유용하게 사용할 수 있도록 API를 개선해야합니다.

이 추론을 따르면, Java와 같은 언어에서 흔히 발생하는 예외를 선언, 포착 및 다시 던지는 "번거 로움"은 종종 가치가 거의 없다는 것이 분명합니다.

Java VM에는 예외를 검사 하지 않았 으며 Java 컴파일러 만 예외를 검사하며 예외 선언이 변경된 클래스 파일은 런타임에 호환됩니다. Java VM 보안은 확인 된 예외로 개선되지 않고 코딩 스타일만으로 향상됩니다.


4
당신의 주장은 그 자체에 반대합니다. "때때로 예외를 잡아야한다"고 API 품질이 좋지 않은 경우, 예외를 확인하지 않고 디자이너가 특정 메소드가 예외를 처리해야한다는 것을 문서화하지 않았는지 알 수 없습니다. 당신이 잘못한 것이 무엇인지, 그리고 어디에서 잡아야하는지 알아내는 AcmeException것이 아니라 던지기 AcmeFileNotFoundError와 행운을 빕니다. 확인 된 예외는 프로그래머에게 잘못된 API 디자인에 대한 보호 수단을 제공합니다.
Eva

1
자바 라이브러리 디자인은 심각한 실수를 범했습니다. '예외 확인'은 파일을 찾을 수 없음, 연결 실패와 같이 예측 가능하고 복구 가능한 우발 상황에 대한 것입니다. 그것들은 저수준의 시스템 고장에 적합하거나 결코 적합하지 않았습니다. 파일을 강제로 열어 보는 것이 좋지만 단일 바이트 쓰기 / SQL 쿼리 실행 실패로 인해 재시도 또는 복구가 적절하지 않습니다. 재시도 또는 복구는 "비즈니스"또는 "요청에서 올바르게 처리됩니다. 예외를 확인한 수준은 무의미하게 어렵습니다. literatejava.com/exceptions/…
토마스 W

17

지난 3 년 동안 비교적 복잡한 응용 프로그램에서 여러 개발자와 협력 해 왔습니다. 적절한 오류 처리와 함께 Checked Exceptions를 자주 사용하는 코드 기반과 그렇지 않은 코드 기반이 있습니다.

지금까지 Checked Exceptions를 사용하여 코드베이스로 작업하는 것이 더 쉽다는 것을 알았습니다. 다른 사람의 API를 사용하는 경우 코드를 호출하고 기록, 표시 또는 무시하여 코드를 호출하고 올바르게 처리 할 때 어떤 종류의 오류 조건을 정확하게 볼 수 있는지 알 수 있습니다 (예, 무시하는 경우가 있습니다) ClassLoader 구현과 같은 예외). 그것은 내가 복구 할 기회를 쓰고있는 코드를 제공합니다. 모든 런타임 예외는 일반적인 오류 처리 코드로 캐시되고 처리 될 때까지 전파됩니다. 실제로 특정 수준에서 처리하고 싶지 않거나 프로그래밍 논리 오류를 고려한 확인 된 예외를 찾으면 RuntimeException에 래핑하여 버블 링합니다. 타당한 이유없이 예외를 삼키지 마십시오.

예외를 확인하지 않은 코드베이스로 작업 할 때 함수를 호출 할 때 무엇을 기대할 수 있는지 미리 알기가 조금 어렵습니다.

이것은 물론 선호도와 개발자 기술의 문제입니다. 프로그래밍과 오류 처리의 두 가지 방법 모두 똑같이 효과적이거나 효과적이지 않을 수 있으므로 One Way가 있다고 말할 수는 없습니다.

대체로 개발자가 많은 대규모 프로젝트에서 Checked Exceptions를 사용하는 것이 더 쉽다는 것을 알았습니다.


6
그렇습니다. 나를 위해 그들은 계약의 필수 부분입니다. API 문서를 자세히 설명하지 않아도 가장 유사한 오류 시나리오를 신속하게 알 수 있습니다.
Wayne Hartman

2
동의하다. 네트워크 호출을 시도 할 때 .Net에서 확인 된 예외의 필요성을 한 번 경험했습니다. 언제라도 네트워크 문제가 발생할 수 있다는 것을 알고 API의 전체 설명서를 읽어 해당 시나리오에 대해 구체적으로 파악해야하는 예외가 무엇인지 찾아야했습니다. C #에서 예외를 확인했다면 즉시 알았을 것입니다. 다른 C # 개발자는 단순한 네트워크 오류로 인해 앱이 중단 될 수 있습니다.
AxiomaticNexus 2016 년

13

예외 카테고리

예외에 대해 이야기 할 때는 항상 Eric Lippert의 Vexing 예외 블로그 기사를 참조하십시오. 그는 다음 범주에 예외를 둡니다.

  • 치명적 -이러한 예외는 귀하의 잘못 이 아닙니다.이를 방지 할 수 없으며 현명하게 처리 할 수 ​​없습니다. 예를 들어 OutOfMemoryError또는 ThreadAbortException.
  • 본 헤드 (Boneheaded) -이 예외 는 당신의 잘못입니다 : 당신은 그것들을 막았어야하고 그것들은 코드의 버그를 나타냅니다. 예를 들어 ArrayIndexOutOfBoundsException, NullPointerException또는 IllegalArgumentException.
  • Vexing- 이러한 예외는 예외가 아니며 귀하의 잘못이 아니며, 예방할 수는 없지만 처리해야합니다. 그들은 같은 던지는 종종 불행한 디자인 결정의 결과 NumberFormatException에서 Integer.parseInt대신 제공의 Integer.tryParseInt구문 분석 실패 부울 거짓을 반환하는 방법을.
  • 외생 적 – 이러한 예외 는 일반적으로 예외 가 아니며, 귀하의 잘못이 아니며, (합리적으로) 예방할 수는 없지만 처리해야합니다 . 예를 들면 다음과 같습니다 FileNotFoundException.

API 사용자 :

  • 치명적 또는 본 헤드 예외를 처리 해서는 안됩니다 .
  • vexing 예외를 처리 해야 하지만 이상적인 API에서는 발생하지 않아야합니다.
  • 외인성 예외 처리 해야합니다 .

확인 된 예외

API 사용자 특정 예외를 처리 해야 한다는 사실 은 호출자와 수신자 사이의 메소드 계약의 일부입니다. 계약은 무엇보다도, 수신자가 기대하는 인수의 수와 유형, 발신자가 기대할 수있는 반환 값의 유형, 그리고 발신자가 처리 할 것으로 예상되는 예외를 지정합니다 .

API에 vexing 예외가 없어야 하기 때문에 메소드 계약의 일부가 되려면 외인성 예외 만 검사 해야합니다 . 상대적으로 적은 예외가 외생 적이므로 모든 API에는 상대적으로 적은 예외가 있습니다.

확인 된 예외는 처리해야하는 . 예외 처리는 삼키는 것만 큼 간단 할 수 있습니다. 그곳에! 예외가 처리됩니다. 기간. 개발자가 그런 식으로 처리하고 싶다면 괜찮습니다. 그러나 그는 예외를 무시할 수 없으며 경고를 받았다.

API 문제

그러나 vexing치명적인 예외 (예 : JCL)를 확인한 API는 API 사용자에게 불필요한 부담을줍니다. 이러한 예외 처리 해야 하지만, 예외는 너무 흔해서 처음에는 예외가 아니 었거나 처리 할 때 수행 할 수있는 것이 없습니다. 그리고 이것은 인해 Java 개발자는 확인 된 예외를 싫어하게됩니다.

또한 많은 API에는 적절한 예외 클래스 계층 구조가 없으므로 모든 종류의 외생 적 예외 원인이 단일 검사 예외 클래스 (예 : IOException . 그리고 이것은 또한 Java 개발자가 확인 된 예외를 싫어하게합니다.

결론

외인성 예외는 귀하의 잘못이 아니며, 예방할 수 없었으며, 처리되어야하는 예외입니다. 이것들은 던져 질 수있는 모든 예외의 작은 부분 집합을 형성합니다. API는 외생 예외검사 하고 다른 모든 예외는 검사하지 않아야합니다. 이를 통해 API를 개선하고 API 사용자에 대한 부담을 덜어 주므로 모든 예외를 포착하고 확인되지 않은 예외를 삼키거나 다시 던질 필요가 줄어 듭니다.

따라서 Java 및 확인 된 예외를 싫어하지 마십시오. 대신, 확인 된 예외를 과도하게 사용하는 API를 싫어하십시오.


계층 구조가 없어서 오용합니다.
TofuBeer

1
FileNotFound 및 JDBC / 네트워크 연결 설정은 우발적 이며 예측 가능하고 복구 가능하므로 확인 된 예외입니다. 대부분의 다른 IOException, SQLExceptions, RemoteException 등은 예측할 수없고 복구 할 수없는 실패 이며 런타임 예외 여야합니다 . 잘못된 Java 라이브러리 디자인으로 인해 우리는 모두이 실수로 가득 찼으며 현재 대부분 Spring & Hibernate (디자인이 올바른)를 사용하고 있습니다.
Thomas W

일반적으로 본 헤드 예외를 처리해야하지만 "처리"라고 부르지 않을 수도 있습니다. 예를 들어, 웹 서버에서 로그를 기록하고 사용자에게 500을 표시합니다. 예외가 예상치 못한 것처럼 버그 수정 전에 할 수있는 모든 것이 있습니다.
maaartinus

6

확인 된 예외는 이상적이지 않으며 약간의 경고가 있지만 목적을 제공합니다. API를 작성할 때이 API와 계약적인 특정 실패 사례가 있습니다. Java와 같이 정적으로 정적으로 유형이 지정된 언어와 관련하여 확인 된 예외를 사용하지 않는 경우 오류 가능성을 전달하기 위해 임시 문서 및 규칙에 의존해야합니다. 그렇게하면 컴파일러가 처리 오류를 가져올 수있는 모든 이점이 제거되고 프로그래머의 선의에 전적으로 의존하게됩니다.

따라서 C #에서와 같이 Checked 예외를 제거하면 어떻게 프로그래밍 방식으로 및 구조적으로 오류 가능성을 전달할 수 있습니까? 클라이언트 코드에 이러한 오류 및 이러한 오류가 발생할 수 있고 처리해야한다고 알리는 방법은 무엇입니까?

확인 된 예외를 처리 할 때 모든 종류의 공포를 듣습니다. 오용되어 있지만 이것은 확실하지만 확인되지 않은 예외입니다. API가 여러 계층으로 쌓여있을 때 몇 년을 기다렸다가 실패를 전달하는 일종의 구조적 수단의 반환을 요구할 것입니다.

예외는 API 레이어의 맨 아래에 예외가 발생하고 호출 오류가 발생할 가능성이 매우 높음에도 불구 하고이 오류가 발생할 가능성을 아무도 알지 못했기 때문에 버블 링 된 경우를 가정하십시오. 그것을 던졌습니다 (예를 들어 VogonsTrashingEarthExcept ...와 달리 FileNotFoundException ...이 경우 처리 할 것이 없기 때문에 처리 여부에 관계가 없습니다).

많은 사람들은 파일을로드 할 수 없다는 것이 거의 항상 프로세스의 끝이라고 말하면서 끔찍하고 고통스러운 죽음으로 죽어야한다고 주장했습니다. 그래, 그래 .. 확실히 ... 알았어. 당신은 무언가를위한 API를 빌드하고 어느 시점에서 파일을로드한다 ... 나는 API 사용자가 응답 할 수만있을 때 ... "내가 언제 누구를 결정할 것인가? 프로그램이 충돌해야합니다! " 물론 예외가 발생하고 추적을 남기지 않거나 Marianna 트렌치보다 스택 추적이 깊은 EletroFlabbingChunkFluxManifoldChuggingException을 남기지 않으면 망설임없이 후자를 가져 가지만 예외를 처리하는 것이 바람직한 방법이라는 것을 의미합니다. ? 우리는 중간에 어딘가에있을 수 없습니까? 예외는 새로운 수준의 추상화로 이동할 때마다 예외가 다시 변환되고 포장되어 실제로 무언가를 의미합니까?

마지막으로, 내가보고있는 대부분의 주장은 "예외를 다루고 싶지 않다. 많은 사람들이 예외를 다루고 싶지 않다. 확인 된 예외로 인해 예외를 처리해야하므로 확인 된 예외를 싫어한다"는 것이다. 지옥 지옥의 틈새로 옮기는 것은 어리석은 일이며 심판과 비전이 부족합니다.

검사 된 예외를 제거하면 함수에 대한 리턴 유형을 제거하고 항상 "anytype"변수를 리턴 할 수 있습니다. 그렇게하면 인생이 훨씬 간단 해집니다.


2
검사 된 예외는 블록 내에서 메소드 호출 중 일부 (또는 어떤) 검사 된 예외가 발생하지 않을 것이라고 선언하는 선언적 수단이있는 경우 유용하며, 그러한 예외는 자동으로 줄 바꿈되고 다시 발생해야합니다. 확인 된 예외를 던지는 것으로 선언 된 메소드에 대한 호출이 예외 처리 속도에 대한 호출 속도 / 반환으로 교환 된 경우 (예상 예외는 거의 정상적인 프로그램 흐름처럼 빠르게 처리 될 수 있음) 훨씬 유용 할 수 있습니다. 그러나 현재 두 상황 모두 적용되지는 않습니다.
supercat

6

실제로, 확인 된 예외는 프로그램의 견고성과 정확성을 향상시킵니다 (인터페이스를 올바르게 선언해야합니다-예외는 기본적으로 특수 반환 유형입니다). 반면에 예외는 "버블 업 (bubble up)"하기 때문에 예외를 변경할 때 많은 메소드 (모든 호출자 및 호출자의 호출자 등)를 변경해야하는 문제가 있습니다. 메소드가 발생합니다.

Java에서 확인 된 예외는 후자의 문제를 해결하지 않습니다. C #과 VB.NET은 목욕물로 아기를 버리십시오.

중간 도로를 이용하는 좋은 방법은 이 OOPSLA 2005 백서 (또는 관련 기술 보고서 )에 설명되어 있습니다.

간단히 말해, 다음과 같이 말할 수 있습니다. method g(x) throws like f(x)즉, g는 f가 던지는 모든 예외를 던집니다. Voila, 계단식 변경 문제없이 예외를 확인했습니다.

학술 논문이지만 확인 된 예외의 이점과 단점이 무엇인지 설명하는 데 도움이되므로 잘 읽도록 권장합니다.


5

이것은 점검 된 예외의 순수한 개념에 대한 논쟁은 아니지만 Java가 사용하는 클래스 계층 구조는 괴물 쇼입니다. 우리는 항상 "예외 (exceptions)"라고 부릅니다 . 언어 사양 에서도 그것을 호출 하기 때문에 정확합니다. 그러나 타입 시스템에서 예외의 이름은 어떻게 표현됩니까?

수업으로 Exception상상 하는가? 글쎄, Exceptions는 예외이고, 마찬가지로 예외는 Exceptions가 아닌 예외를 제외하고는 Exception다른 예외는 실제로는 예외이기 때문에 다른 예외는 Error예외입니다. 때, 그리고 때로는 당신이해야 할 경우를 제외하고는 결코 잡을 수 없습니다. 당신은 또한도 다른 예외 정의 할 수 있기 때문에 그게 전부가 아니다 제외 Exception의도 Error의하지만 단지 Throwable예외.

다음 중 "확인 된"예외는 무엇입니까? Throwable들 그들은 또한 인 경우 제외시켰다 예외를 체크 Error되지 않은 예외되는 s가하고있다 Exception또한의, Throwable하나 개의 예외도 그에게 거기를 제외하고, S 및 확인이 끝난 예외의 주요 유형을 것입니다있는 경우 그들은 또한 RuntimeException그 체크되지 않는 예외의 다른 종류이기 때문에,이야.

무엇입니까 RuntimeException? 이름에서 알 수 있듯이 모든 예외와 같은 예외이며 Exception실제로 모든 예외와 마찬가지로 런타임에서 발생합니다. 단, RuntimeException예외가 발생 Exception하지 않아야하기 때문에 다른 런타임과 비교하여 예외적 이라는 점을 제외하고 는 예외입니다. 당신이 바보 같은 실수를 할 때, RuntimeExceptions는 결코 Errors가 아니기 때문에 예외적으로 잘못되었지만 실제로는 그렇지 않은 것들을위한 것입니다 Error. for RuntimeErrorException은 제외하고 실제로는 RuntimeExceptionfor Error입니다. 그러나 모든 예외가 어쨌든 잘못된 상황을 나타내는 것은 아닙니까? 그렇습니다. ThreadDeath문서에서 "정상 발생"이라고 설명하고 예외가 아닌 예외를 제외하고 는 예외입니다.Error

어쨌든, 모든 예외를 중간에서 Errors (예외 실행 예외의 경우에는 검사되지 않음)와 Exceptions (예외 실행 오류가 적은 경우에는 그렇지 않은 경우를 제외하고 검사 됨) 로 나누기 때문에 이제 두 개가 필요합니다. 여러 예외 각각의 다른 종류. 따라서 우리는 IllegalAccessErrorand IllegalAccessException, and InstantiationErrorand InstantiationException, and NoSuchFieldErrorand NoSuchFieldException, and NoSuchMethodErrorand NoSuchMethodException, and ZipErrorand가 필요 ZipException합니다.

예외가 점검 되더라도 컴파일러를 부정하고 점검하지 않고 던질 수있는 방법은 항상 있습니다. 당신이 할 경우, 당신은 얻을 수 UndeclaredThrowableException그것이로 던질 수있는 다른 사례를 제외하고 UnexpectedException, 또는 UnknownException(관련이있는 UnknownError경우에만 "심각한 예외"에 대한 인), 또는 ExecutionException, 또는 InvocationTargetException, 또는 ExceptionInInitializerError.

아, 그리고 우리는 8의 새로운 세련되지 자바를 잊지 말아야 UncheckedIOExceptionRuntimeException검사는 포장하여 창 밖으로 개념을 확인 예외를 던질 수 있도록 설계 예외 IOExceptionI에 의한 예외 / 일으키지 않는 O 오류 ( IOError즉 존재하지만 예외 또한 처리하기가 매우 어렵 기 때문에 확인하지 않아도됩니다.

감사합니다 Java!


2
내가 말할 수있는 한,이 답변은 "자바의 예외는 엉망이다"라는 말만으로도 아이러니하고 논쟁의 여지가있는 재미있는 방법으로 만 말한다. 하지 말아야 할 것은 프로그래머가 왜 이런 것들이 어떻게 작동하는지 이해하려고하지 않는 이유를 설명하는 것입니다. 또한 실제 사례 (적어도 내가 처리 할 수있는 경우)에서 프로그래머가 의도적으로 삶을 더 어렵게 만들려고 시도하지 않으면 예외가 당신이 설명한 것처럼 복잡하지 않습니다.
CptBartender

5

문제

예외 처리 메커니즘에서 볼 수있는 최악의 문제 는 코드 복제가 대규모 로 발생한다는 것입니다 ! 솔직하게 말하자 : 대부분의 프로젝트에서 95 %의 시간 동안 개발자가 실제로 예외적으로해야하는 것은 사용자에게 (어떤 경우에는 개발 팀에게 e) 스택 추적이있는 메일). 따라서 일반적으로 예외가 처리되는 모든 장소에서 동일한 코드 / 블록이 사용됩니다.

확인 된 예외 유형에 대해 각 catch 블록에 간단한 로깅을 수행한다고 가정 해 봅시다.

try{
   methodDeclaringCheckedException();
}catch(CheckedException e){
   logger.error(e);
}

일반적인 예외라면 더 큰 코드베이스에 수백 개의 try-catch 블록이있을 수 있습니다. 이제 콘솔 로깅 대신 팝업 대화 상자 기반 예외 처리를 도입하거나 추가로 전자 메일을 개발 팀에 보내야한다고 가정 해 봅시다.

잠깐만 ... 코드에서 수백 개의 위치를 ​​모두 편집할까요?! 당신은 내 요점을 얻는다 :-).

해결책

이 문제를 해결 하기 위해 수행 한 것은 예외 처리 를 중앙 집중화 하기 위해 예외 처리기 (EH라고도 함) 개념을 도입하는 것이 었습니다 . 예외를 처리해야하는 모든 클래스에는 예외 처리기 인스턴스가 의존성 주입 프레임 워크에 의해 주입됩니다 . 따라서 일반적인 예외 처리 패턴은 다음과 같습니다.

try{
    methodDeclaringCheckedException();
}catch(CheckedException e){
    exceptionHandler.handleError(e);
}

이제 예외 처리를 사용자 정의하려면 단일 위치 (EH 코드)에서 코드 만 변경하면됩니다.

물론 더 복잡한 경우에 우리는 EH의 여러 서브 클래스를 구현하고 DI 프레임 워크가 제공하는 기능을 활용할 수 있습니다. DI 프레임 워크 구성을 변경하여 EH 구현을 전체적으로 쉽게 전환하거나 특별한 예외 처리 요구가있는 클래스 (예 : Guice @Named 주석 사용)가있는 EH 구현을 제공 할 수 있습니다.

이렇게하면 개발 및 릴리스 버전의 응용 프로그램에서 예외 처리 동작을 차별화 할 수 있습니다 (예 : 개발-오류 로깅 및 응용 프로그램 중지, prod-오류를 더 자세히 기록하고 응용 프로그램이 계속 실행되도록).

마지막으로

마지막으로 예외가 최상위 예외 처리 클래스에 도달 할 때까지 예외를 "위로"전달하면 동일한 유형의 중앙 집중화를 얻을 수 있습니다. 그러나 그로 인해 코드가 복잡해지고 메소드의 서명이 생성 되고이 스레드에서 다른 사람들이 언급 한 유지 관리 문제가 발생합니다.


6
그들에게 유용한 무언가를하기 위해 예외가 발명되었다. 로그 파일에 파일을 쓰거나 예쁜 창을 렌더링하는 것은 원래 문제가 이것으로 해결되지 않기 때문에 유용하지 않습니다. 유용한 일을하려면 다른 솔루션 전략을 시도해야합니다. 예 : 서버 AI에서 데이터를 가져올 수없는 경우 서버 B에서 시도하십시오. 또는 알고리즘 A가 힙 오버 플로우를 생성하는 경우 알고리즘 B가 훨씬 느리지 만 성공할 수 있습니다.
ce

2
@ceving 예, 이론 상으로는 모두 훌륭합니다. 그러나 이제 단어를 연습 해 봅시다. 실제 프로젝트에서 얼마나 자주 수행하는지 정직하게 대답하십시오. catch이 실제 프로젝트 의 블록 중 어떤 부분 이 exceptin과 함께 "유용한"기능을 수행합니까? 10 %가 좋을 것입니다. 예외를 생성하는 일반적인 문제는 존재하지 않는 파일, OutOfMemoryErrors, NullPointerExceptions, 데이터베이스 제약 조건 무결성 오류 등에서 구성을 읽으려고하는 것과 같습니다. 실제로 모든 예외에서 정상적으로 복구하려고합니까? 나는 당신을 믿지 않습니다 :). 종종 회복 할 방법이 없습니다.
Piotr Sobczyk 2014 년

3
@PiotrSobczyk : 프로그램이 suer 요청의 결과로 어떤 조치를 취하고 시스템 상태에서 아무 것도 손상되지 않은 방식으로 작업이 실패하는 경우, 작업을 완료 할 수 없음을 사용자에게 알리는 것이 매우 유용합니다 상황을 다루는 방법. C # 및 .net에서 가장 큰 예외는 시스템 상태의 항목이 손상되었는지 확인할 수있는 일관된 방법이 없다는 것입니다.
supercat

4
맞습니다, @PiotrSobczyk. 대부분 예외에 대한 응답으로 수행 할 수있는 올바른 조치는 트랜잭션을 롤백하고 오류 응답을 반환하는 것입니다. "예외 해결"에 대한 아이디어는 우리가 가지고 있지 않아야하고 캡슐화를 위반하지 않는 지식과 권위를 의미합니다. 우리의 응용 프로그램이 DB가 아닌 경우 DB를 수정 하려고 시도해서는 안됩니다 . 깨끗이 실패하고 잘못된 데이터를 작성하지 않는 것이 유용합니다 .
Thomas W

@PiotrSobczyk 어제, "오브젝트를 읽을 수 없습니다"예외 (기본 데이터베이스가 소프트웨어보다 먼저 업데이트 되었기 때문에 발생합니다-결코 일어날 수는 없지만 인적 오류로 인한 것임)는 데이터베이스의 이전 버전은 객체의 이전 버전을 가리 켰습니다.
시조

4

Anders는 확인 된 예외의 함정과 Software Engineering 라디오의 에피소드 97 에서 C #에서 제외시킨 이유에 대해 이야기합니다 .


4

c2.com에 대한 저의 글은 여전히 ​​원래 형식과 거의 동일합니다. c2.com CheckedExceptionsAreIncompatibleWithVisitorPattern

요약하자면:

방문자 패턴과 그 친척은 간접 호출자와 인터페이스 구현이 예외에 대해 알고 있지만 인터페이스와 직접 호출자가 알 수없는 라이브러리를 형성하는 인터페이스 클래스입니다.

CheckedExceptions의 기본 가정은 선언 된 모든 예외는 해당 선언으로 메소드를 호출하는 모든 지점에서 발생할 수 있다는 것입니다. VisitorPattern은이 가정이 잘못되었음을 밝힙니다.

이와 같은 경우에 체크 된 예외의 최종 결과는 런타임에 컴파일러의 체크 된 예외 제약 조건을 본질적으로 제거하는 많은 쓸모없는 코드입니다.

근본적인 문제에 관해서는 :

내 일반적인 아이디어는 최상위 처리기가 예외를 해석하고 적절한 오류 메시지를 표시해야한다는 것입니다. 나는 거의 항상 IO 예외, 통신 예외 (어떤 이유로 API가 구별) 또는 작업 치명적 오류 (백업 서버의 프로그램 버그 또는 심각한 문제)를 보이므로 스택 추적을 심각하게 허용하면 너무 어렵지 않아야합니다 서버 문제.


1
인터페이스에 DAGNodeException과 같은 것이 있어야합니다. 그런 다음 IOException을 포착하여이를 DAGNodeException으로 변환하십시오. public void call (DAGNode arg) throws DAGNodeException;
TofuBeer

2
@TofuBeer, 그것이 바로 내 요점입니다. 예외를 계속 래핑하고 래핑 해제하는 것이 확인 된 예외를 제거하는 것보다 나쁩니다.
Joshua

2
글쎄 우리는 완전히 동의하지 않지만 ... 기사는 여전히 런타임 예외가 발생할 때 사용자에게 스택 추적을 표시하지 못하게하는 방법에 대한 실제 기본 질문에 대답하지 않습니다.
TofuBeer

1
@TofuBeer-실패했을 때 사용자에게 실패했음을 알리는 것이 맞습니다! '널 (null)'또는 불완전한 / 잘못된 데이터로 실패를 "종이 처리"하는 것 이외의 대안은 무엇입니까? 성공한 척은 거짓말로, 상황을 악화시킵니다. 고 신뢰성 시스템에서 25 년의 경험을 가진 재시도 로직은 신중하고 적절한 경우에만 사용해야합니다. 또한 몇 번이나 다시 시도하더라도 방문자가 다시 실패 할 것으로 예상합니다. 비행기를 타지 않는 한 동일한 알고리즘의 두 번째 버전으로 바꾸는 것은 비현실적이며 불가능합니다 (어쨌든 실패 할 수 있음).
Thomas W

4

답변되지 않은 질문 만 해결하려면 :

예외 서브 클래스 대신 RuntimeException 서브 클래스를 처리하면 무엇을 잡아야하는지 어떻게 알 수 있습니까?

질문에는 의심스러운 추론 IMHO가 포함됩니다. API가 던지는 것을 알려주기 때문에 모든 경우에 동일한 방식으로 처리한다는 의미는 아닙니다. 다시 말해, 잡아야 할 예외는 예외를 발생시키는 구성 요소를 사용하는 컨텍스트에 따라 다릅니다.

예를 들면 다음과 같습니다.

데이터베이스에 대한 연결 테스터를 작성 중이거나 사용자의 유효성을 검사하기 위해 XPath를 입력 한 경우 작업에서 발생하는 모든 확인 및 확인되지 않은 예외를 포착하고보고하려고합니다.

그러나 처리 엔진을 작성하는 경우 NPE와 동일한 방식으로 XPathException (확인)을 처리 할 것입니다. 워커 스레드의 맨 위로 실행되도록하고 나머지 배치를 건너 뛰고 로그하십시오. 문제를 진단하거나 진단을 위해 지원 부서에 보냅니다.


2
바로 그거죠. 예외 처리 방식이 쉽고 간단합니다. Dave가 말했듯이 올바른 예외 처리는 일반적으로 높은 수준 에서 수행 됩니다 . "초기 던져, 늦게 잡아"가 원칙입니다. 확인 된 예외는이를 어렵게 만듭니다.
Thomas W

4

이 기사 는 내가 읽은 Java의 예외 처리에 관한 최고의 텍스트입니다.

검사되지 않은 예외보다 검사되지 않은 것을 선호하지만이 선택은 매우 격렬하고 강력한 논거를 기반으로 설명됩니다.

여기에 기사 내용을 너무 많이 인용하고 싶지는 않지만 (전체로 읽는 것이 가장 좋습니다)이 스레드에서 확인되지 않은 예외 옹호자의 주장 대부분을 다루고 있습니다. 특히이 논쟁 (꽤 인기있는 것으로 보입니다)은 다음과 같습니다.

예외는 API 레이어의 맨 아래에 예외가 발생하고 호출 오류가 발생할 가능성이 매우 높음에도 불구 하고이 오류가 발생할 가능성을 아무도 알지 못했기 때문에 버블 링 된 경우를 가정하십시오. 그것을 던졌습니다 (예를 들어 VogonsTrashingEarthExcept ...와 달리 FileNotFoundException ...이 경우 처리 할 것이 없기 때문에 처리 여부에 관계가 없습니다).

저자는 "응답":

모든 런타임 예외를 잡아서 응용 프로그램의 맨 위에 전달할 수 없다고 가정하는 것은 완전히 잘못된 것입니다. (...) 시스템 / 비즈니스 요구 사항에 따라 명확하게 처리해야하는 모든 예외적 인 조건에 대해 프로그래머는 조건을 파악한 후 조건을 파악한 후 수행 할 작업을 결정해야합니다. 이는 컴파일러 경고를 기반으로하지 않고 응용 프로그램의 실제 요구에 따라 엄격하게 수행해야합니다. 다른 모든 오류는 오류가 기록 될 최상위 처리기로 자유롭게 전파 될 수 있어야하며 적절한 조치 (아마도 종료)가 수행됩니다.

그리고 주요 생각이나 기사는 다음과 같습니다.

소프트웨어의 오류 처리와 관련하여 유일하게 안전하고 정확한 가정은 존재하는 모든 서브 루틴 또는 모듈에서 오류가 발생할 수 있다는 것입니다!

따라서 " 아무도이 오류가 발생할 수 있음을 알지 못하면 해당 프로젝트에 문제가있는 것입니다. 이러한 예외는 최소한 가장 일반적인 예외 처리기 (예 :보다 구체적인 처리기에서 처리하지 않는 모든 예외를 처리하는 예외 처리기)에 의해 처리되어야합니다.

슬프게도 많은 사람들이이 위대한 기사를 발견하는 것 같지 않습니다.


4

확인 된 예외는 원래 형태로 실패가 아닌 비상 사태를 처리하려는 시도였습니다. 주목할만한 목표는 특정 예측 가능한 포인트 (연결할 수 없음, 파일을 찾을 수 없음 등)를 강조하고 개발자가 이러한 점을 처리하도록하는 것이 었습니다.

원래 개념에 포함되지 않은 것은 광범위한 체계적 및 복구 불가능한 오류를 선언하는 것이 었습니다. 이러한 실패는 확인 된 예외로 선언되지 않았습니다.

일반적으로 코드에서 오류가 발생할 수 있으며 EJB, 웹 및 Swing / AWT 컨테이너는 가장 외부의 "실패한 요청"예외 처리기를 제공하여 이미이를 충족시킵니다. 가장 기본적인 올바른 전략은 트랜잭션을 롤백하고 오류를 반환하는 것입니다.

한 가지 중요한 점은 런타임 및 검사 예외가 기능적으로 동일하다는 것입니다.점검 된 예외가 수행 할 수있는 처리 또는 복구가 없으며 런타임 예외는 수행 할 수 없습니다.

"체크 된"예외에 대한 가장 큰 주장은 대부분의 예외를 수정할 수 없다는 것입니다. 간단한 사실은 우리가 파산 한 코드 / 서브 시스템을 소유하지 않는다는 것입니다. 우리는 구현을 볼 수 없으며 책임을지지 않으며 해결할 수 없습니다.

애플리케이션이 DB가 아닌 경우 DB를 수정하려고 시도해서는 안됩니다. 그것은 캡슐화원칙을 위반할 것 입니다.

특히 문제는 JDBC (SQLException)와 EJB를위한 RMI (RemoteException) 영역이었습니다. 원래의 "체크 된 예외"개념에 따라 고정 가능한 우발성을 식별하는 대신, 실제로 고칠 수없는 이러한 광범위한 시스템 신뢰성 문제는 널리 선언되어야합니다.

Java 디자인의 또 다른 심각한 결함은 예외 처리가 가능한 가장 높은 "비즈니스"또는 "요청"레벨에 올바르게 배치되어야한다는 것입니다. 여기서의 원칙은 "빨리 던져서 늦게 잡아라"입니다. 확인 된 예외는 거의 수행하지 않지만 방해가됩니다.

우리는 자바에서 수천 가지의 아무것도하지 않는 try-catch 블록을 요구하는 명백한 문제가 있으며, 상당 부분 (40 % +)이 잘못 코딩되었습니다. 이들 중 어느 것도 진정한 처리 또는 신뢰성을 구현하지는 않지만 주요 코딩 오버 헤드를 부과합니다.

마지막으로 "체크 된 예외"는 FP 기능 프로그래밍과 거의 호환되지 않습니다.

"즉시 처리"에 대한 그들의 주장은 "캐치 늦게"예외 처리 모범 사례와 루프 / 또는 제어 흐름을 추상화하는 FP 구조와 상충됩니다.

많은 사람들이 "처리 된"예외에 대해 이야기하지만 모자를 통해 이야기하고 있습니다. 성공 을 가장 하기 위해 널 (null), 불완전하거나 잘못된 데이터로 실패한 후에도 계속 처리하는 것은 아무 것도 처리하지 않습니다. 가장 낮은 형태의 엔지니어링 / 신뢰성 과실입니다.

깨끗하게 실패하면 예외를 처리하기위한 가장 기본적인 올바른 전략입니다. 트랜잭션 롤백, 오류 기록 및 사용자에게 "실패"응답보고는 올바른 관행이며, 가장 중요한 것은 잘못된 비즈니스 데이터가 데이터베이스에 커밋되지 않도록 방지하는 것입니다.

예외 처리를위한 다른 전략은 비즈니스, 하위 시스템 또는 요청 수준에서 "다시 시도", "다시 연결"또는 "건너 뛰기"입니다. 이 모든 것은 일반적인 안정성 전략이며 런타임 예외와 함께 잘 작동합니다.

마지막으로, 잘못된 데이터로 실행하는 것보다 실패하는 것이 훨씬 바람직합니다. 계속하면 원래 원인과 거리가 멀고 디버그하기 어려운 2 차 오류가 발생합니다. 또는 결국 잘못된 데이터가 커밋됩니다. 사람들은 해고 당합니다.

참조 :
- http://literatejava.com/exceptions/checked-exceptions-javas-biggest-mistake/


1
내 요점은 일반적인 전략으로 제대로 실패하는 것 입니다. 검사되지 않은 예외는 캐치 블록이 강제로 개입되지 않으므로 도움이됩니다. 그러면 캐치 및 오류 로깅을 코드베이스 전체에서 수천 번 잘못 코딩하지 않고 몇 개의 가장 바깥 쪽 처리기로 남겨 둘 수 있습니다 (실제로 버그를 숨기는 것임) . 임의의 실패의 경우 검사되지 않은 예외가 가장 정확합니다. 불충분 한 자금과 같은 예측 가능한 결과 인 우발 사태 는 합법적으로 확인할 가치가있는 유일한 예외입니다.
토마스 W

1
내 대답은 이미이 문제를 해결합니다. 가장 먼저, 1) 가장 바깥 쪽 실패 처리기는 모든 것을 포착해야합니다. 그 외에도 특정 식별 된 사이트의 경우에만 2) 특정 예상되는 우발 상황이 발생하면 즉각 처리 된 사이트에서 처리 및 처리 될 수 있습니다. 즉, 파일을 찾을 수없고 자금이 부족할 때 등 자금을 회수 할 수 있습니다. 캡슐화 원리는 외부 층이 내부 깊은 곳의 고장을 이해 / 복구 할 책임이 없음을 의미합니다. 셋째, 3) 다른 모든 것들은 바깥쪽으로 던져 져야합니다. 가능하다면 체크하지 마십시오.
Thomas W

1
가장 바깥 쪽 처리기는 예외를 잡아서 기록하고 "실패한"응답을 반환하거나 오류 대화 상자를 표시합니다. 매우 간단하고 전혀 정의하기 어렵지 않습니다. 요점은 즉시 및 로컬에서 복구 할 수없는 모든 예외 는 캡슐화 원칙으로 인해 복구 할 수없는 실패라는 것입니다. 알아야 할 코드를 복구 할 수없는 경우 전체 요청이 깨끗하고 올바르게 실패합니다. 이것이 올바른 방법입니다.
Thomas W

1
잘못되었습니다. 최 외각 처리기의 작업은 '요청'경계에 오류명확하게 기록하고 오류기록 하는 것입니다. 손상된 요청이 제대로 실패하고 예외가보고되며 스레드가 다음 요청을 계속 처리 할 수 ​​있습니다. 이러한 가장 바깥 쪽 핸들러는 Tomcat, AWT, Spring, EJB 컨테이너 및 Java '메인'스레드의 표준 기능입니다.
Thomas W

1
요청 경계 또는 가장 바깥 쪽 처리기에서 "정품 버그"를보고하는 것이 왜 위험한가요 ??? 저는 정확한 신뢰성 공학이 실제로 중요한 시스템 통합 및 신뢰성 분야에서 자주 일하고 "확인되지 않은 예외"접근 방식을 사용합니다. 나는 당신이 실제로 토론하고있는 것이 확실하지 않습니다. 실제로 확인되지 않은 예외 방식으로 3 개월을 보내고 느낌을 얻은 다음 더 논의 할 수있는 것처럼 보입니다. 감사.
Thomas W

4

사람들이 이미 언급했듯이 검사 된 예외는 Java 바이트 코드에 존재하지 않습니다. 다른 구문 검사와 달리 단순히 컴파일러 메커니즘입니다. 컴파일러가 중복 조건에 대해 불평하는 것처럼 확인 된 예외를 많이 봅니다 if(true) { a; } b;. 도움이 되긴하지만 의도적으로이 작업을 수행했을 수도 있으므로 경고를 무시하겠습니다.

문제의 사실은, 당신이 확인 된 예외를 강제하고 다른 모든 사람들이 당신이 만든 규칙 때문에 당신을 미워하는 담보 손해라면 모든 프로그래머가 "올바른 일을하도록"강요 할 수 없다는 것입니다.

나쁜 프로그램을 수정하십시오! 언어를 허용하지 않도록 수정하려고하지 마십시오! 대부분의 사람들에게 "예외에 대해 무언가를하는 것"은 실제로 사용자에게 예외를 알려주는 것입니다. 확인되지 않은 예외에 대해서도 사용자에게 알릴 수 있으므로 확인 된 예외 클래스를 API에서 제외하십시오.


맞습니다. 나는 도달 할 수없는 코드 (오류를 생성하는)와 예측 가능한 결과가있는 조건부 사이의 차이점을 강조하고 싶었습니다. 이 주석은 나중에 제거하겠습니다.
Holger

3

확인 된 예외의 문제는 인터페이스의 한 구현조차도 예외를 사용하는 경우 인터페이스의 메소드에 예외가 종종 첨부된다는 것입니다.

확인 된 예외의 또 다른 문제점은 오용되는 경향이 있다는 것입니다. 이것의 완벽한 예는 java.sql.Connectionclose()방법입니다. Connection이 완료 되었다고SQLException 이미 명시 적으로 언급 했지만을 던질 수 있습니다 . 어떤 정보가 close ()가 관심을 가질만한 정보를 전달할 수 있습니까?

일반적으로 connection을 닫을 때 *다음과 같이 보입니다.

try {
    conn.close();
} catch (SQLException ex) {
    // Do nothing
}

또한 다양한 구문 분석 방법과 NumberFormatException에서 시작하지 마십시오 ... 예외를 던지지 않는 .NET의 TryParse는 사용하기가 훨씬 쉽습니다 .Java로 돌아가는 것이 고통 스럽습니다 (Java와 Java를 모두 사용합니다) 내가 일하는 C #).

*추가 설명으로 PooledConnection의 Connection.close ()는 연결을 닫지 않지만 확인 된 예외이기 때문에 여전히 SQLException을 잡아야합니다.


2
그렇습니다. 어떤 운전자도 할 수 있습니다 ... 문제는 오히려 "프로그래머가 왜 신경 써야 하는가?"입니다. 그는 어쨌든 데이터베이스 액세스를 완료했습니다. 문서는 close ()를 호출하기 전에 항상 현재 트랜잭션을 commit () 또는 rollback ()해야한다고 경고합니다.
Powerlord

많은 사람들이 파일을 닫으면 예외를 던질 수 없다고 생각합니다 ... stackoverflow.com/questions/588546/… 중요한 사건이 없다는 것을 100 % 확신하십니까?
TofuBeer

나는 아무 경우가 없다는 것을 100 % 확신 문제와 발신자가 있다고 하지 않을 시도 / 캐치에 넣어가.
Martin

1
연결을 닫는 훌륭한 예, 마틴! 나는 단지 당신에게 말을 할 수 있습니다 : 우리가 우리가 연결로 끝났다고 명시 적으로 언급했다면 왜 우리가 그것을 막을 때 무슨 일이 일어나고 있는지 귀찮게해야합니다. 프로그래머가 예외가 발생하더라도 실제로 신경 쓰지 않는 것과 같은 더 많은 경우가 있으며 그는 예외가 옳습니다.
Piotr Sobczyk

1
@PiotrSobczyk : 일부 SQL 드라이버는 트랜잭션을 시작한 후 연결을 닫았지만 확인하거나 롤백하지 않으면 연결이 끊어 질 수 있습니다. IMHO, 스 쿼킹은 문제를 무시하는 것보다 낫습니다. 적어도 스 쿼킹으로 인해 다른 예외를 잃지 않는 경우가 있습니다.
supercat

3

프로그래머 는 메소드를 올바르게 사용하기 위해 메소드에서 발생할 수있는 모든 예외 를 알아야 합니다. 따라서 예외 중 일부만으로 머리 위로 때리는 것이 부주의 한 프로그래머가 오류를 피하는 데 도움이되는 것은 아닙니다.

슬림 한 이점은 부담스러운 비용보다 중요합니다 (특히 인터페이스 서명을 지속적으로 수정하는 것이 실용적이지 않은 더 크고 유연하지 않은 코드 기반의 경우).

정적 분석은 훌륭하지만 신뢰할 수있는 정적 분석은 종종 프로그래머의 엄격한 작업을 유연하게 요구합니다. 비용-편익 계산이 있으며 컴파일 시간 오류로 이어지는 검사를 위해 막대를 높게 설정해야합니다. IDE가 메소드가 던질 수있는 예외 (피할 수없는 예외 포함)를 전달하는 역할을 수행하는 것이 더 도움이됩니다. 강제 예외 선언 없이는 신뢰할 수 없지만 대부분의 예외는 여전히 문서에 선언되어 있으며 IDE 경고의 신뢰성은 그다지 중요하지 않습니다.


2

나는 이것이 훌륭한 질문이며 전혀 논쟁의 여지가 없다고 생각합니다. 제 3 자 라이브러리는 일반적으로 검사되지 않은 예외를 던져야한다고 생각합니다 . 이것은 라이브러리에 대한 의존성을 분리 할 수 ​​있음을 의미합니다 (즉, 예외를 다시 던지거나 Exception일반적으로 나쁜 연습을 하지 않아도 됨 ). Spring의 DAO 레이어 가 이에 대한 훌륭한 예입니다.

그들이 할 수 있다면 다른 한편으로는, 핵심 자바 API에서 예외는 일반적 BE 체크해야 지금까지 처리 할 수. FileNotFoundException또는 (나의 마음에 드는) 가져 가라 InterruptedException. 이러한 조건은 거의 항상 구체적으로 처리 해야합니다 (즉,에 대한 반응이에 대한 반응 InterruptedException과 같지 않음 IllegalArgumentException). 예외를 확인한다는 사실 때문에 개발자는 조건을 처리 할 수 ​​있는지 여부를 생각해야합니다. (저는 InterruptedException제대로 처리하는 것을 거의 보지 못했습니다 !)

한가지 더 – a RuntimeException가 항상 "개발자가 뭔가 잘못한 것"은 아닙니다. enum사용 을 시도 할 때 잘못된 인수 예외가 발생 하며 해당 이름 valueOf이 없습니다 enum. 개발자가 반드시 실수는 아닙니다!


1
예, 개발자의 실수입니다. 그들은 분명히 올바른 이름을 사용하지 않았으므로 돌아가서 코드를 수정해야합니다.
AxiomaticNexus 2016 년

@AxiomaticNexus 정상적인 개발자는 enum단순히 enum객체를 사용하기 때문에 멤버 이름을 사용 하지 않습니다. 따라서 잘못된 이름은 가져 오기 파일 등 무엇이든 외부에서 나올 수 있습니다. 그러한 이름을 다루는 한 가지 가능한 방법 MyEnum#valueOf은 IAE에 전화 하여 붙잡는 것입니다. 또 다른 방법은 미리 채워진을 사용하는 Map<String, MyEnum>것이지만 구현 세부 사항입니다.
maaartinus

@maaartinus 열거 형 멤버 이름이 외부에서 오는 문자열없이 사용되는 경우가 있습니다. 예를 들어, 모든 멤버를 동적으로 반복하여 각 멤버에 대해 무언가를 수행하려는 경우. 또한 줄이 외부에서 나오는지 여부는 관련이 없습니다. 개발자는 x 문자열을 "MyEnum # valueOf"로 전달할 때 전달하기 전에 오류가 발생하는지 알기 위해 필요한 모든 정보를 가지고 있습니다. 어쨌든 오류를 일으켰을 때 x 문자열을 "MyEnum # valueOf"로 전달하면 개발자가 실수로 실수 한 것입니다.
AxiomaticNexus 18시 52 분

2

다음은 확인 된 예외에 대한 한 가지 주장입니다 (joelonsoftware.com).

그 이유는 1960 년대 이후로 유해한 것으로 간주되는 "고토 (goto 's)"보다 예외가 코드의 한 지점에서 다른 지점으로 갑작스럽게 점프하기 때문이라고 생각하기 때문입니다. 실제로 그들은 goto보다 훨씬 나쁩니다.

  • 소스 코드에서는 보이지 않습니다. 예외를 던지거나 던지지 않을 수있는 함수를 포함하여 코드 블록을 살펴보면 어떤 예외가 어디에서 발생하는지 확인할 수있는 방법이 없습니다. 이것은 신중한 코드 검사조차도 잠재적 인 버그를 나타내지 않음을 의미합니다.
  • 함수에 대해 가능한 많은 종료점을 작성합니다. 올바른 코드를 작성하려면 함수를 통해 가능한 모든 코드 경로를 고려해야합니다. 예외를 발생시킬 수있는 함수를 호출 할 때마다이를 즉시 포착하지 못하면, 갑자기 종료되어 데이터가 일관성이없는 상태로 유지되거나 다른 코드 경로가 아닌 다른 코드 경로에 의해 발생하는 깜짝 버그가 발생할 수 있습니다 생각 해봐

3
+1 당신은 당신의 대답에 논쟁을 요약하고 싶습니까? 그들은 프로그램 전체에 흩어져있는 보이지 않는 고토 및 일상의 초기 출구와 같습니다.
MarkJ

13
그것은 일반적으로 예외에 대한 논쟁입니다.
Ionuț G. Stan

10
당신은 실제로 기사를 읽었습니까! 먼저 그는 일반적으로 예외에 대해 이야기하고, 두 번째로 "그들은 소스 코드에서 보이지 않습니다"섹션이 UNCHECKED 예외에 적용됩니다. 이것은 확인 된 예외의 요점입니다. 그래서 당신은 어떤 코드가 무엇을 던지는지를 알고 있습니다.
Newtopian

2
@Eva 그들은 동일하지 않습니다. goto 문으로 goto키워드를 볼 수 있습니다 . 루프를 사용하면 닫는 괄호 또는 break또는 continue키워드를 볼 수 있습니다 . 그들 모두는 현재 방법의 한 지점으로 이동합니다. 그러나 항상 throw현재 메서드가 아니라 호출하는 다른 메서드 (간접적으로)에 있기 때문에 항상을 볼 수는 없습니다.
finnw

5
@finnw 함수 자체는 goto의 한 형태입니다. 일반적으로 호출하는 함수가 어떤 함수를 호출하는지 알 수 없습니다. 기능없이 프로그래밍 한 경우 보이지 않는 예외에는 문제가 없습니다. 즉, 문제는 예외와 관련이 없으며 일반적으로 예외에 대한 유효한 인수가 아닙니다. 에러 코드가 빠르다고 말하고 모나드가 더 깨끗하다고 ​​말할 수 있지만 goto 인수는 어리 석습니다.
Eva

2

확인 된 예외가 필요하지 않다는 증거는 다음과 같습니다.

  1. Java에서 작동하는 많은 프레임 워크. JDBC 예외를 검사되지 않은 예외로 랩핑하여 메시지를 로그에 던지는 Spring처럼
  2. Java 플랫폼 에서조차도 Java 다음에 오는 많은 언어-사용하지 않습니다.
  3. 확인 된 예외는 클라이언트가 예외를 throw하는 코드를 사용하는 방법에 대한 친절한 예측입니다. 그러나이 코드를 작성하는 개발자는 코드 클라이언트가 작업중인 시스템 및 비즈니스에 대해 전혀 알지 못합니다. 예를 들어 체크 된 예외를 강제로 발생시키는 Interfcace 메소드. 시스템에 100 개의 구현이 있으며 50 개 또는 90 개의 구현이이 예외를 발생시키지 않지만 클라이언트가 해당 인터페이스를 참조하는 경우 클라이언트는 여전히이 예외를 포착해야합니다. 이러한 50 또는 90 구현은 예외를 로그에 넣는 자체 예외를 처리하는 경향이 있습니다 (이것은 좋은 동작입니다). 우리는 어떻게해야합니까? 로그에 메시지를 보내는 모든 작업을 수행하는 백그라운드 로직이 더 좋습니다. 그리고 코드 클라이언트 인 경우 예외 처리가 필요하다고 생각되면 처리하겠습니다.
  4. Java에서 I / O로 작업 할 때의 또 다른 예는 파일이 존재하지 않으면 모든 예외를 확인하도록 강요합니까? 내가 어떻게해야합니까? 존재하지 않으면 시스템은 다음 단계로 진행되지 않습니다. 이 메소드의 클라이언트는 해당 파일에서 예상되는 내용을 얻지 못합니다. 런타임 예외를 처리 할 수 ​​있습니다. 그렇지 않으면 먼저 확인 된 예외를 확인하고 로그에 메시지를 넣은 다음 메소드에서 예외를 버려야합니다. 아니요 ... 아니요-RuntimeEception으로 자동으로하는 것이 좋습니다. 자동으로 켜집니다. 수동으로 처리하는 것이 의미가 없습니다. 로그에 오류 메시지가 표시되어 기쁩니다 (AOP가 도움이 될 수 있습니다 .. java를 수정하는 것). 결국 시스템이 최종 사용자에게 팝업 메시지를 표시해야한다고 결정하면 문제가 아니라 표시합니다.

Java가 I / O와 같은 핵심 라이브러리로 작업 할 때 사용할 항목을 선택할 수 있다면 기뻤습니다 . Like는 RuntimeEception으로 랩핑 된 동일한 클래스의 두 사본을 제공합니다. 그러면 사람들이 무엇을 사용할지 비교할 수 있습니다 . 그러나 지금은 많은 사람들이 Java 또는 다른 언어에서 일부 프레임 워크를 사용하는 것이 좋습니다. 스칼라처럼 JRuby도 마찬가지입니다. 많은 사람들은 단지 SUN이 옳았다 고 믿습니다.


1
두 가지 버전의 클래스를 가지기보다는 코드 블록에 의한 메소드 호출이 특정 유형의 예외를 던질 것으로 예상되지 않으며 그러한 예외는 지정된 수단을 통해 랩되어야한다는 간결한 방법이 있어야합니다. 다시 던지기 (기본적으로 RuntimeException적절한 내부 예외를 사용하여 새로 만들기 ) 안타깝게도 throws후자의 조치가 더 정확할 때 내부 메소드의 예외를 랩핑하는 것보다 외부 메소드에 내부 메소드 의 예외 를 갖는 것이 더 간결하다는 것은 불행한 일입니다 .
supercat

2

아무도 언급하지 않은 한 가지 중요한 점은 인터페이스와 람다 식을 방해하는 방법입니다.

을 정의한다고 가정 해 보겠습니다 MyAppException extends Exception. 응용 프로그램에서 발생하는 모든 예외에서 상속 된 최상위 예외입니다. 모든 메소드는 throws MyAppException어느 것이 약간 불쾌하지만 관리 가능하다고 선언합니다 . 예외 처리기는 예외를 기록하고 어떻게 든 사용자에게 알립니다.

귀하의 인터페이스가 아닌 일부 인터페이스를 구현할 때까지 모두 괜찮아 보입니다. 분명히 throw 의도를 선언하지 않으므로 MyApException컴파일러는 예외를 throw 할 수 없습니다.

그러나 예외가 확장 RuntimeException되면 인터페이스에 문제가 없습니다. 원하는 경우 JavaDoc에서 예외를 자발적으로 언급 할 수 있습니다. 그러나 그 외에는 예외 처리 계층에 잡히기 위해 자동으로 모든 것을 통해 버블 링합니다.


1

우리는 C #의 수석 설계자에 대한 언급을 보았습니다.

다음은 확인 된 예외를 언제 사용해야하는지에 대한 Java 담당자의 다른 관점입니다. 그는 다른 사람들이 언급 한 많은 부정적인 점을 인정합니다 : 효과적인 예외


2
Java에서 확인 된 예외에 대한 문제는 더 깊은 문제에서 비롯됩니다. 즉, 인스턴스의 속성이 아니라 예외의 TYPE에 너무 많은 정보가 캡슐화됩니다. "체크 된"예외가 throw / catch 사이트의 속성이고 예외적으로 코드 블록을 벗어나는 검사 된 예외를 검사 된 예외로 유지해야하는지 또는 볼 수 있는지 여부를 확인하는 것이 유용 할 것입니다. 확인되지 않은 예외로 모든 둘러싸는 블록에 의해; 마찬가지로 catch 블록은 확인 된 예외 만 원하도록 지정할 수 있어야합니다.
supercat

1
존재하지 않는 키에 액세스하려고 시도하는 경우 특정 유형의 예외를 발생 시키도록 사전 검색 루틴이 지정되었다고 가정하십시오. 클라이언트 코드가 그러한 예외를 포착하는 것이 합리적 일 수 있습니다. 그러나 조회 루틴이 사용하는 일부 메소드가 조회 루틴이 예상하지 않는 방식으로 동일한 유형의 예외를 발생시키는 경우 클라이언트 코드는이를 포착하지 않아야합니다. 점검은 예외 인스턴스 의 속성이며 , 사이트를 던지고 사이트를 잡으면 그러한 문제를 피할 수 있습니다. 클라이언트는 해당 유형의 '확인 된'예외를 포착하여 예기치 않은 예외를 피합니다.
supercat

0

나는 예외 처리에 대해 많이 읽었습니다. (대부분의 경우) 실제로 확인 된 예외의 존재에 대해 행복하거나 슬프다 고 말할 수는 없습니다. 낮은 수준의 코드에서 확인 된 예외 , OS 등) 및 상위 수준 API / 응용 프로그램 수준에서 확인되지 않은 예외.

그들 사이에 선을 그리는 것이 쉽지 않더라도 확인 된 예외를 많이 포장하지 않고 동일한 지붕 아래 여러 API / 라이브러리를 통합하는 것은 실제로 성가 시거나 어렵습니다. 일부 예외를 잡아서 현재 상황에서 더 의미있는 다른 예외를 제공 해야하는 것이 유용합니다.

내가 작업하고있는 프로젝트는 많은 라이브러리를 가져 와서 동일한 API, 확인되지 않은 예외를 완전히 기반으로하는 API로 통합합니다.이 프레임 워크는 처음에는 확인 된 예외로 가득 차 있고 확인되지 않은 몇 가지만있는 고급 API를 제공합니다 예외 (초기화 예외, ConfigurationException 등)는 매우 친절 하지 않다고 말해야합니다 . 대부분의 경우 처리 방법을 모르는 예외를 포착하거나 다시 발생시켜야하거나, 특히 단일 클라이언트가있는 클라이언트 측에서는주의를 기울이지 않아야합니다 (예외를 무시해서는 안 됨) 클릭하면 10 개의 가능한 (확인 된) 예외가 발생할 수 있습니다.

현재 버전 (3 번째)은 확인되지 않은 예외 만 사용하며, 포착되지 않은 모든 것을 처리하는 전역 예외 처리기가 있습니다. API는 예외 처리기를 등록하는 방법을 제공합니다. 예외 처리기는 예외로 판단되는 경우 (대부분의 경우) 누군가에게 로그 및 알림을 의미하거나 다른 예외를 의미 할 수 있습니다 (예 : AbortException, 이는 현재 실행 스레드를 중단하고 원하지 않는 오류를 기록하지 않음을 의미합니다. 물론 모든 사용자 정의 스레드를 해결하려면 try {...} catch (all)로 run () 메서드를 처리해야합니다.

공공 무효 실행 () {

try {
     ... do something ...
} catch (Throwable throwable) {
     ApplicationContext.getExceptionService().handleException("Handle this exception", throwable);
}

}

WorkerService를 사용하여 모든 작업을 처리하는 작업 (Runnable, Callable, Worker)을 예약하는 경우에는 필요하지 않습니다.

물론 이것은 단지 내 의견 일 뿐이며, 옳지 않을 수도 있지만, 나에게 좋은 접근 방법처럼 보입니다. 나는 그것이 나에게 좋다고 생각하는 것이 다른 사람들에게도 좋다면 프로젝트를 발표 한 후에 볼 것이다. :)

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.