Java에서 확인 된 예외는 무엇입니까? [닫은]


14

Java의 확인 된 예외는 수년 동안 나쁜 언론을 얻었습니다. 신호는 문자 그대로 세계에서 유일하게 언어가 사용된다는 것입니다 (Groovy 및 Scala와 같은 다른 JVM 언어는 포함하지 않음). Spring 및 Hibernate와 같은 유명한 Java 라이브러리도 사용하지 않습니다.

나는 개인적으로 ( 레이어 간의 비즈니스 로직에서) 그것들을 한 가지 용도로 찾았 지만 그렇지 않으면 꽤 반체제 예외입니다.

내가 모르는 다른 용도가 있습니까?


모든 Java 코어 라이브러리는 확인 된 예외를 상당히 광범위하게 사용합니다.
Joonas Pulakka

3
@Joonas 알아요, 아파요!
Brad Cupit

답변:


22

우선, 다른 프로그래밍 패러다임과 마찬가지로 제대로 작동하려면 올바르게 수행해야합니다.

들어 체크 된 예외의 장점은 벌써 합리적으로 예상 할 수있는 일반적인 어떤 문제가 나를 위해 결정했다 자바 런타임 라이브러리의 저자가에서 처리 할 수 있다는 것입니다 전화 최상위 캐치 - 인쇄 - 반대 (포인트 이러한 문제를 처리하는 방법을 가능한 한 빨리 고려하십시오.

나는 오류 복구에 대해 가능한 한 빨리 생각하도록 강요함으로써 코드를 더욱 강력하게 만들기 때문에 예외를 확인하는 것을 좋아한다.

,보다 정확하게는 에 따라 매우 초기의 말에 반대하는 과정에서 이상한 코너 케이스를 고려하는 저를 강제로이보다 강력한 내 코드를 만든다 "파일이 아직 존재하지 않는 경우 아차, 내 코드는 처리하지 않습니다" 생산 오류가 발생하면 처리하기 위해 코드를 다시 작성해야합니다. 기존 코드에 오류 처리를 추가하는 것은 시작부터 바로 수행하는 것이 아니라 유지 보수에 도달 할 때 쉽지 않은 작업이므로 비용이 많이들 수 있습니다.

그것은 누락 된 파일이 치명적인 것입니다 수 있습니다 및 화염에 충돌하는 프로그램을 야기한다, 그러나 당신은 그 결정에을

} catch (FileNotFoundException e) {
  throw new RuntimeException("Important file not present", e);
}

이것은 또한 매우 중요한 부작용을 보여줍니다. 예외를 포장 하면 stack-trace에 설명을 추가 할 수 있습니다 ! 누락 된 파일 이름,이 메소드에 전달 된 매개 변수 또는 기타 진단 정보에 대한 정보를 추가 할 수 있고 정보가 스택 추적에 바로 존재하기 때문에 매우 강력 합니다. 프로그램이 충돌했을 때 얻는다.

사람들은 "우리는 이것을 재현하기 위해 디버거에서 이것을 실행할 수있다"고 말할 수도 있지만, 나는 매우 자주 생산 오류 를 재현 할 수 없으며, 본질적으로 작업이 위태로운 경우를 제외하고 생산에서 디버거를 실행할 수 없다는 것을 알았습니다 .

스택 추적에 정보가 많을수록 좋습니다. 확인 된 예외는 해당 정보를 조기에 얻는 데 도움이됩니다.


편집 : 이것은 도서관 디자이너에게도 해당됩니다. 매일 사용하는 하나의 라이브러리에는 사용하기보다 지루하지 않게 훨씬 잘 디자인 된 많은 확인 된 예외가 포함되어 있습니다.


+1. Spring의 디자이너는 많은 Hibernate 예외를 검사되지 않은 예외로 변환하는 데 능숙했다.

참고 : Frank Sommers는이 스레드 에서 내결함성 소프트웨어가 종종 동일한 메커니즘에 의존한다고 언급했습니다 . 아마도 답변을 복구 가능한 사례와 치명적인 사례로 세분화 할 수 있습니다.
rwong

@ rwong, 당신이 생각하는 것을 더 자세히 설명해 주시겠습니까?

11

실제로 확인 된 예외가 무엇인지 설명하는 두 가지 좋은 답변이 있습니다. 그러나 의도는 실제로 가치가 있기 때문에 이론상 의도 한 것을 조사하는 것도 가치가있다.

확인 된 예외는 실제로 언어를보다 안전하게 보호하기위한 것입니다. 정수 곱셈과 같은 간단한 방법을 고려하십시오. 이 메소드의 결과 유형은 정수라고 생각할 수 있지만 엄밀히 말하면 결과는 정수 또는 오버 플로우 예외입니다. 정수 결과 자체를 메소드의 리턴 유형으로 고려해도 함수의 전체 범위를 표현하지는 않습니다.

이러한 관점에서 볼 때, 확인 된 예외가 다른 언어로 들어 가지 않았다고 말하는 것은 사실이 아닙니다. 그들은 단지 자바가 사용한 형태를 취하지 않았습니다. Haskell 응용 프로그램에서는 대수 데이터 형식을 사용하여 함수의 성공과 실패를 구분하는 것이 일반적입니다. 이것이 예외는 아니지만 그 의도는 확인 된 예외와 거의 동일합니다. API 소비자가 성공하지 못한 경우 성공을 모두 처리하도록 설계된 API입니다. 예 :

data Foo a =
     Success a
   | DidNotWorkBecauseOfA
   | DidNotWorkBecauseOfB

이것은 프로그래머에게 함수가 성공 외에 두 가지 가능한 추가 결과가 있음을 알려줍니다.


유형 안전에 관한 확인 된 예외에 대해서는 +1입니다. 나는 그 아이디어를 한 번도 들어 본 적이 없지만 너무 의미가 있습니다.
Ixrec

11

IMO, 예외가 어떤 결함이 구현되어 확인 할 수 꽤 괜찮은 아이디어왔다 (완전히 다른 상황 -하지만 정말 현재의 상황에서조차 좋은 생각이 아니다).

좋은 생각은 컴파일러가 프로그램에 던질 가능성이있는 모든 예외가 포착되는지 확인하도록하는 것이 좋을 것입니다. 결함이있는 구현은 그렇게하기 위해 Java가 확인 된 예외를 던지기 위해 선언 된 모든 것을 호출하는 클래스에서 직접 예외를 처리하도록한다는 것입니다. 예외 처리의 가장 기본적인 아이디어 (및 장점) 중 하나는 오류가 발생하는 경우 특정 오류와 관련이없는 중간 코드 계층이 그 존재를 완전히 무시할 수 있다는 것입니다. 확인 된 예외 (Java로 구현 됨)는 허용하지 않으므로 예외 처리의 주요 이점 (기본?)을 파괴합니다.

이론적으로, 그들은 프로그램 전체에 대해서만 예외를 적용함으로써 확인 된 예외를 유용하게 만들 수있었습니다. 즉, 프로그램을 "빌드"하는 동안 프로그램의 모든 제어 경로 트리를 작성하십시오. 트리의 다양한 노드에는 1) 생성 가능한 예외와 2) 포착 할 수있는 예외가 주석으로 표시됩니다. 프로그램이 올바른지 확인하기 위해 나무를 걷다가 나무의 어느 수준에서나 발생 된 모든 예외가 나무의 높은 수준에서 잡혔는 지 확인합니다.

그들이 그렇게하지 않은 이유 는 (어쨌든 추측 하듯이) 그렇게하는 것은 엄청나게 어려울 것이기 때문입니다. 사실, 나는 누군가가 그것을 아주 간단하게 할 수있는 빌드 시스템을 작성 했는지 의심합니다. ") 언어 / 시스템. Java의 경우 동적 클래스 로딩과 같은 것은 다른 많은 경우보다 훨씬 어렵습니다. 더 나쁜 것은 (C와 달리) Java는 (적어도 보통) 정적으로 컴파일되거나 실행 파일에 연결되지 않습니다. 즉 , 최종 사용자가 실제로 프로그램을 실행하기 위해 프로그램을로드하기 시작할 때까지 시스템에서 실제로 이러한 종류의 시행을 시도하려는 글로벌 인식은 없습니다.

이 시점에서 시행하는 것은 몇 가지 이유로 비실용적입니다. 우선, 기껏해야 Java에 대한 가장 큰 가장 일반적인 불만 중 하나 인 시작 시간을 연장 할 수 있습니다. 둘째, 많은 일을하려면 프로그래머가 문제를 해결할 수있을 정도로 빨리 문제를 감지해야합니다. 사용자가 프로그램을로드 할 때 너무 늦어서 좋은 일을하기에는 너무 늦습니다. 그 시점에서 유일한 선택은 문제를 무시하거나 예외 가 있을 가능성이있는 경우 프로그램을로드 / 실행하지 않는 것입니다. 잡히지 않았다.

확인 된 예외는 쓸모없는 것보다 나쁘지만 확인 된 예외에 대한 대체 설계는 훨씬 더 나쁩니다. 확인 된 예외에 대한 기본 아이디어는 좋은 것처럼 보이지만 실제로는 좋지 않으며 Java에 특히 적합 하지 않습니다 . C ++과 같은 것은 일반적으로 리플렉션 / 동적 클래스 로딩과 거의 비슷한 완전한 실행 파일로 컴파일 / 링크되어 있으므로 약간의 가능성이 있습니다 (물론, 솔직히 말해서 동일한 종류의 혼란없이 올바르게 적용하더라도) 현재 Java에서 발생하는 원인은 아마도 최신 기술을 넘어서는 것입니다).


예외를 직접 처리해야한다는 최초의 초기 진술은 이미 거짓입니다. throws 문을 추가하면됩니다. 그러면 throws 문이 부모 유형일 수 있습니다. 또한 실제로 처리해야한다고 생각하지 않으면 간단히 RuntimeException으로 변환 할 수 있습니다. IDE는 일반적으로 두 가지 작업을 모두 도와줍니다.
Maarten Bodewes

2
@owlstead : 고마워. 아마도 거기에있는 문구에 더주의를 기울 였을 것입니다. 요점은 실제로 모든 예외적 인 수준의 코드가 통과 할 수있는 모든 예외를 인식 해야하기 때문에 실제로 예외 를 잡아야 하는 것은 아닙니다. 나머지 부분은 코드를 쉽고 빠르게 만들 수있는 도구를 사용한다고해서 코드를 혼란스럽게한다는 사실을 변경하지는 않습니다.
Jerry Coffin

확인 된 예외는 실패 와는 달리 성공 이외의 예측 가능하고 복구 가능한 결과 인 우발적 인 예측 불가능한 저수준 / 시스템 문제에 대한 것입니다. JDBC 연결을 여는 중 FileNotFound 또는 오류가 모두 우발 상황으로 간주되었습니다. 불행히도, 자바 라이브러리 디자이너들은 완전히 실수를하고 다른 모든 IO 및 SQL 예외도 'checked'클래스에 할당했습니다. 이것들은 거의 완전히 회복 할 수 없지만. literatejava.com/exceptions/…
토마스 W

@owlstead : 확인 된 예외는 호출 코드의 중간 호출 코드에서 예상 되는 경우 호출 스택의 중간 계층에서만 발생합니다 . IMHO, 확인 된 예외는 호출자가 예외를 잡거나 예상 여부를 표시 해야한다면 좋은 일이되었을 것입니다 . 예기치 않은 예외는에서 UnexpectedException파생 된 형식 으로 자동 래핑되어야합니다 RuntimeException. "투구"와 "기대하지 않음"은 모순되지 않습니다. 경우 foo가 발생 BozException하고 전화 bar, 그게 기대 의미하지 않는다 bar던져 BozException.
supercat

10

그들은 정말로 성가신 프로그래머에게 좋고 예외 삼키기를 장려합니다. 예외의 절반은 오류를 처리하는 기본 방법이 정해져서 처리 할 수없는 오류 조건을 명시 적으로 전파하는 것에 대해 생각할 필요가 없다는 것입니다. (정확한 기본값은 코드의 어느 곳에서나 오류를 처리하지 않으면 오류가 발생하지 않는다는 것을 효과적으로 주장했으며 잘못하면 정상 종료와 스택 추적이 남는 것입니다.) 이. 그들은 C에서 오류를 명시 적으로 전파해야한다고 생각합니다.


4
쉬운 수정 : throws FileNotFoundException. 하드 픽스 :catch (FileNotFoundException e) { throw RuntimeException(e); }
Thomas Eding

5

확인 된 예외가 약간 실패한 실험이라고 말하는 것이 공정하다고 생각합니다. 그들이 잘못한 곳은 레이어링을 끊었다는 것입니다.

  • 모듈 A는 모듈 B 위에 구축 될 수 있습니다.
  • 모듈 B는 모듈 C 위에 구축 될 수 있습니다.
  • 모듈 C는 오류를 식별하는 방법을 알고있을 수 있습니다.
  • 모듈 A가 오류 처리 방법을 알고있을 수 있습니다.

이제 A와 C로 제한 될 수있는 오류에 대한 지식이 이제 B에 흩어져 야하므로 우려의 분리가 잘되지 않습니다.

Wikipedia에서 확인 된 예외에 대한 좋은 토론 이 있습니다.

그리고 Bruce Eckel도 그것에 관한 좋은 기사 를 가지고 있습니다. 인용문은 다음과 같습니다.

[T] 그는 프로그래머에게 쌓을 수있는 임의의 규칙, 문제를 해결하는 데 아무런 관련이없는 규칙, 프로그래머가 생성하는 속도를 느리게한다. 그리고 이것은 선형 인자가 아닌 지수 인 것으로 보입니다.

C ++의 경우 모든 메소드에 throws스펙 절이 있으면 멋진 최적화를 할 수 있다고 생각합니다. 그래도 RuntimeExceptions확인되지 않았기 때문에 Java가 어쨌든 그러한 이점을 가질 수 있다고 생각하지 않습니다 . 현대의 JIT는 어쨌든 코드를 최적화 할 수 있어야합니다.

AspectJ의 멋진 기능 중 하나는 예외 완화입니다. 확인 된 예외를 검사되지 않은 예외로 전환 할 수 있습니다. 특히 레이어링을 향상시킵니다.

아마도 그것은 자바가 검사 한 수이 문제의 모든 통해 갔다 아이러니 null대신, 훨씬 더 가치되었을 수 있습니다 .


하하, 그들이하지 않은 결정으로 null을 확인하는 것에 대해 결코 생각하지 못했습니다 ... 그러나 마침내 Objective-C에서 작업 한 후에는 null이 호출 된 메소드를 가질 수있게하는 것이 선천적 문제가 아니라는 것을 이해했습니다.
Dan Rosenstark

3
null-checking은 훨씬 더 큰 고통입니다. 항상 확인해야합니다. 그리고 이유가 무엇인지, 이유가 무엇인지 잘 알려지지 않았습니다.

5

나는 예외를 좋아한다.

그러나 나는 그들의 잘못 사용으로 끊임없이 기뻐하고 있습니다.

  1. 흐름 처리에 사용하지 마십시오. 무언가를 시도하고 대신 무언가를 수행하는 트리거로 예외를 사용하는 코드는 원하지 않습니다. 예외는 무언가를 작성하고 귀찮게 할 수 없었기 때문에 메모리 등을 사용해야하는 객체이기 때문입니다. 전화하기 전에 if () 확인의 종류. 그것은 단지 게으르고 영광스러운 예외에 나쁜 이름을줍니다.

  2. 삼키지 마십시오. 이제까지. 어떤 경우 에라도. 최소한 예외가 발생했음을 나타 내기 위해 로그 파일에 무언가를 붙입니다. 예외를 삼키는 코드를 통해 길을 추적하는 것은 악몽입니다. 다시 말하지만, 강력한 예외를 반박하게해서 예외 삼키는 사람을 저주하십시오!

  3. OO 모자를 착용 한 상태에서 예외를 처리하십시오. 의미있는 계층 구조로 고유 한 Exception 개체를 만듭니다. 비즈니스 로직과 예외 사항을 함께 처리하십시오. 나는 시스템의 새로운 영역에서 시작하면 코딩 30 분 이내에 Exception을 서브 클래스 화해야한다는 것을 알았으므로 요즘에는 Exception 클래스를 작성하여 시작합니다.

  4. '프레임 워크'비트 코드를 작성하는 경우 모든 초기 인터페이스가 적절한 경우 새 예외를 처리하도록 작성되었는지 확인하고 코더가 코드를 수행 할 때 수행 할 작업 대신 샘플 코드가 있는지 확인하십시오. IOException을 throw하지만 작성하려는 인터페이스에서 'ReportingApplicationException'을 발생 시키려고합니다.

예외 처리 방법을 익힌 후에는 뒤돌아 보지 않을 것입니다.


2
좋은 지침은 +1입니다. 또한 적절한 initCause경우 예외를 발생시킨 예외와 함께 예외를 사용 하거나 초기화하십시오. 예 : 쓰기에 실패한 경우에만 예외가 필요한 I / O 유틸리티가 있습니다. 그러나 쓰기에 실패 할 수있는 여러 가지 이유가 있습니다 (액세스, 쓰기 오류 등을 얻을 수 없음). 원인 문제와 함께 사용자 지정 예외를 발생시켜 원래 문제를 삼키지 않도록하십시오.
Michael K

3
나는 무례하고 싶지 않지만 이것이 CHECKED 예외와 어떤 관련이 있습니까? :)
palto

확인 된 예외 의 자체 계층 구조를 작성하도록 다시 작성할 수 있습니다 .
Maarten Bodewes

4

확인 된 예외는 ADA에도 있습니다.

(이 게시물에는 대면 할 수있는 강력한 믿음이 담겨 있습니다.)

프로그래머는 마음에 들지 않고 불평하거나 예외 삼키기 코드를 작성합니다.

작업이 실패 할뿐만 아니라 실패 모드 / 효과 분석을 수행하고이를 미리 결정할 수 있으므로 확인 된 예외가 존재합니다.

파일 읽기가 실패 할 수 있습니다. RPC 호출이 실패 할 수 있습니다. 네트워크 IO가 실패 할 수 있습니다. 구문 분석 할 때 데이터 형식이 잘못 될 수 있습니다.

코드의 "행복한 길"은 쉽습니다.

대학에서 좋은 "행복한 길"코드를 작성할 수있는 사람을 알고있었습니다. 가장자리 케이스 중 어느 것도 효과가 없었습니다. 요즘 그는 오픈 소스 회사에서 Python을하고 있습니다. 그런가 말했다.

확인 된 예외를 처리하지 않으려는 경우 실제로 말하는 것은

While I'm writing this code, I don't want to consider obvious failure modes.

The User will just have to like the program crashing or doing weird things.

But that's okay with me because 

I'm so much more important than the people who will have to use the software

in the real, messy, error-prone world.

After all, I write the code once, you use it all day long.

따라서 확인 된 예외는 더 많은 작업을 의미하기 때문에 프로그래머가 좋아하지 않을 것입니다.

물론 다른 사람들도 그 일을하기를 원했을 것입니다.

그들은 파일 서버가 고장 나거나 USB 스틱이 죽더라도 정답을 원했을 것입니다.

프로그래밍 커뮤니티에서 일하는 것은 소프트웨어를 작성해야 할 때 인생을 편하고 즐겁게 할 수있는 프로그래밍 언어를 사용해야한다는 것은 이상한 생각입니다. 당신은 직업적인 재즈 즉흥 연주에 관여하지 못하게하는 누군가의 문제를 해결하고 있습니다.

아마추어 프로그래머 (돈을 위해 프로그래밍하지 않는 사람) 인 경우 C # 또는 다른 언어로 프로그래밍하여 예외를 제외하고 자유롭게 프로그래밍하십시오. 도대체, 로고에서 중간 남자와 프로그램을 잘라내십시오. 거북이로 바닥에 예쁜 무늬를 그릴 수 있습니다.


6
거기에 도착했다.
Adam Lear

2
+1 "최고의 사례 중 어느 것도 효과가 없었습니다. 요즘 그는 오픈 소스 회사를 위해 Python을하고 있습니다. Nuff는 말했습니다." 클래식
NimChimpsky

1
@palto : Java 쉽지 않은 경로를 강요 합니다. 큰 차이입니다. C #의 경우 "예외가 문서화되어 있습니다"라고 말하고 손을 씻으십시오. 그러나 프로그래머는 오류가 발생하기 쉽습니다. 그들은 물건을 잊어 버립니다. 코드를 작성할 때 컴파일러가 알려줄 수있는 균열을 100 % 상기시키고 싶습니다.
Thomas Eding

2
@ThomasEding Java는 메소드가 호출되는 예외를 강제로 처리합니다. 실제로 호출 코드에서 그것에 대해 무언가를하고 싶고 일반적으로 응용 프로그램의 오류 처리 계층에 예외를 버블 링하려고합니다. 그런 다음 런타임 예외에서 예외를 마무리하거나 직접 예외를 만들어야합니다. 게으른 프로그래머에게는 세 번째 옵션이 있습니다. 걱정하지 않기 때문에 무시하십시오. 그렇게하면 아무도 오류가 발생했는지 알지 못하며 소프트웨어에는 실제로 이상한 버그가 있습니다. 그 세 번째는 확인되지 않은 예외로 발생하지 않습니다.
palto

3
@ThomasEding 위의 모든 인터페이스를 변경하여 구현 세부 사항을 응용 프로그램의 모든 계층에 불필요하게 표시합니다. 예외가 복구하고자하는 인터페이스에서만 가능할 수 있습니다. 일부 구성 파일이 누락되어 getPeople-method에 IOException을 추가하고 싶지 않습니다. 이해가되지 않습니다.
palto

4

확인 된 예외는 사람들이 소스에 가까운 오류를 처리하도록 권장해야합니다. 소스에서 멀어 질수록 실행 중에 더 많은 기능이 종료되고 시스템이 일관성이없는 상태가 될 가능성이 높습니다. 또한 실수로 잘못된 예외를 잡을 가능성이 높습니다.

안타깝게도 사람들은 예외를 무시하거나 증가하는 던지기 사양을 추가하는 경향이 있습니다. 이 두 가지 모두 확인 된 예외가 권장하는 점을 놓치고 있습니다. 그것들은 OO로 만드는 많은 Getter 및 Setter 함수를 사용하기 위해 절차 코드를 변환하는 것과 같습니다.

본질적으로 확인 된 예외는 코드에서 어느 정도의 정확성을 입증하려고합니다. 정적 타이핑과 거의 같은 아이디어입니다. 코드가 실행되기 전에 특정 사항이 올바른지 증명하려고합니다. 문제는 그 모든 추가 증거에 노력이 필요하며 그 노력이 가치가 있다는 것입니다.


2
"예외 무시"는 종종 정확합니다. 여러 번 예외에 대한 최선의 대응은 앱이 중단되도록하는 것입니다. 이 관점에 대한 이론적 근거는 Bertrand Meyer의 객체 지향 소프트웨어 구성을 참조하십시오 . 그는 예외가 올바르게 (계약 위반에 대해) 사용되면 본질적으로 두 가지 올바른 응답이 있음을 보여줍니다. 자세한 내용은 Meyer를 읽으십시오. 주석으로 요약하기는 어렵습니다.
Craig Stuntz

1
@Craig Stuntz, 예외를 무시함으로써 나는 그것을 삼키는 것을 의미했습니다.
Winston Ewert

아, 그건 달라 나는 당신이 그들을 삼키지 말아야한다는 것에 동의합니다.
Craig Stuntz

"예외를 무시하는 것이 종종 맞습니다. 예외에 대한 가장 좋은 반응은 앱이 중단되도록하는 것입니다.": 실제로 응용 프로그램에 따라 다릅니다. 웹 응용 프로그램에서 예외를 발견하지 못한 경우 고객이 웹 페이지에 오류 메시지를보고하고 몇 분 내에 버그 수정을 배포 할 수 있다는 최악의 상황이 발생할 수 있습니다. 비행기가 착륙하는 동안 예외가 발생하면 비행기를 조종하고 회복하는 것이 좋습니다.
Giorgio

@Giorgio, 매우 사실입니다. 비행기 또는 이와 유사한 경우 복구하는 가장 좋은 방법은 시스템을 다시 부팅하는 경우 궁금합니다.
Winston Ewert
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.