Java 애플리케이션에서 런타임 예외 발생


12

저는 고객을 위해 기술 책임자 역할을하는 엔터프라이즈 Java 응용 프로그램을 설계하는 계약자로 일하고 있습니다. 응용 프로그램은 최종 사용자가 사용하며 우리가 떠날 때 응용 프로그램을 지원할 지원 팀이 있습니다.

내가 일하고있는 다른 기술 담당자는 예외 처리로 인해 코드가 더러워 질 것이라는 인상을 받고 있습니다. 시스템은 서비스 계층에서만 확인 된 예외를 처리하고 나머지 코드는 다른 모든 계층에서 런타임 예외를 발생시켜 검사되지 않은 예외를 처리 할 필요가 없습니다.

비즈니스 애플리케이션에서 확인되지 않은 예외를 발생시켜야하는 이유는 무엇입니까?

런타임 예외에 대한 과거의 경험에서 :

1) 검사되지 않은 예외는 Javadoc에서도 코드가 표시되지 않으므로 코드를 예측할 수 없게 만듭니다.

2) 비즈니스 응용 프로그램에서 검사되지 않은 예외를 throw하는 것은 의미가 없습니다. 던질 때 사용자가 직접 직면 할 때 사용자에게 어떻게 설명해야합니까? 나는 500 -Internal Error. Contact Administrator최종 사용자 또는 응용 프로그램을 관리하는 지원 팀에게 아무것도 의미하지 않는 웹 응용 프로그램을 충분히 보았습니다 .

3) 런타임 예외를 던지면 예외를 던지는 클래스의 사용자가 소스 코드를 통해 디버그하고 예외가 발생한 이유를 알 수 있습니다. 런타임 예외의 Javadoc이 문서화 된 경우에만 피할 수 있습니다.


서비스 계층이 무엇인지 설명 할 수 있습니까? 레이어가 사용자와 가장 먼 거리에 있습니까?
Manoj R

이 질문이 왜 그렇게 적합하지 않습니까?
Bjarke Freund-Hansen

@Manoj R : 둘 다. 서비스 티어 또는 계층은 DB 기술 및 클라이언트 프리젠 테이션의 세부 사항과 분리 된 비즈니스 규칙 및 로직이 실행되는 곳입니다.
Michael Borgwardt

6
확인되지 않은 예외 [...]는 Javadoc에서도 나타나지 않습니다. => @throws태그로 문서화하면 나타납니다 . 그건 그렇고 좋은 습관입니다.
assylias

4
@SureshKoya Effective Java, 항목 62 : 각 메소드에서 발생한 모든 예외를 문서화하십시오. 추출 : Javadoc @throws태그를 사용하여 메소드가 던질 수있는 각각의 점검되지 않은 예외를 문서화하지만 메소드 선언에 점검되지 않은 예외를 포함시키기 위해 throws 키워드를 사용하지 마십시오.
assylias

답변:


13

확인 된 예외는 언어 디자인에 실패한 것입니다. 그것들은 매우 유출 된 추상화와 더티 코드를 갖도록 강요합니다. 가능한 한 피해야합니다.

당신의 요점에 관해서 :

1) 확인 된 예외로 인해 코드가 더러워지고 어디에서나 나타나기 때문에 예측할 수 없습니다 .

2) 확인 된 예외가 사용자에게 어떻게 더 잘 표시됩니까? 확인 된 예외와 확인되지 않은 예외의 유일한 차이점은 기술적 인 것이며 소스 코드에만 영향을 미칩니다.

3) 스택 추적에 대해 들어 본 적이 있습니까? 확인 여부에 관계없이 예외가 발생한 위치를 정확하게 알려줍니다. 실제로, 확인 된 예외는 종종 랩핑되어 더 길고 못생긴 스택 추적으로 이어 지거나 랩핑이 잘못되어 전체적으로 손실되기 때문에 디버깅에 더 나쁜 경향이 있습니다.

두 가지 종류의 예외가 있습니다 : "정상적으로"발생하고 일반적으로 발생하는 곳과 매우 가깝게 처리되는 것, 실제로 예외적이고 매우 높은 계층에서 일반적으로 처리 될 수있는 것 (현재 작업을 중단하고 기록 / 오류 표시).

확인 된 예외는 예외가 정의 된 시점에서이 구별을 언어 구문에 넣으려는 시도였습니다. 이것의 문제는

  • 구별은 실제로 예외를 던지는 코드가 아닌 호출자 에게 달려 있습니다.
  • 예외의 의미 적 의미와 완전히 직교하지만 클래스 계층 구조와 연결하면 두 가지를 혼합해야합니다.
  • 예외의 요점은 자동으로 오류를 잃거나 중간 수준에서 코드를 오염시키지 않으면 서 어떤 수준에서 오류를 포착할지 결정할 수 있다는 것입니다. 확인 된 예외는 두 번째 이점을 잃습니다.

1. 점검되지 않은 예외의 경우, 호출로 인해 점검되지 않은 결과조차도 알 수 없습니다. 2. "예외의 의미 적 의미와 완전히 직교하지만 클래스 계층 구조에 연결하면 둘을 혼합해야합니다"라고 말했을 때 클래스 계층 구조 대신 호출 계층 구조를 의미한다고 가정합니다.
randominstanceOfLivingThing

2
@Suresh Koya : 아니요, 클래스 계층 구조를 의미했습니다. 선언 SQLException extends ExceptionSQLExceptionDB 액세스와 관련이 있기 때문에 오류 를 던지도록 선택한다는 것은 자동으로 예외를 확인한다는 의미입니다. 그리고 Javadoc 주석에서 확인되지 않은 예외를 문서화 할 수 있습니다. 다른 모든 언어에서 잘 작동합니다.
Michael Borgwardt

1
@MichaelBorgwardt "체크 된 예외는 언어 디자인에 실패한 경험입니다."에 대한 자세한 내용을 읽고 싶지 않다면 개인적인 의견입니까? 확실한 링크는 큰 도움이 될 것입니다.
Vipin

2
@Vipin : 내 개인적인 의견이지만 Bruce Eckel과 같은 많은 사람들이 공유하는 의견 : mindview.net/Etc/Discussions/CheckedExceptions-Java 가 소개 된 이후 20 년 동안 다른 언어가 확인 된 예외를 채택하지 않았다는 사실 스스로를 위해 ...
Michael Borgwardt

2

내 관점은 어떤 유형의 예외가 발생하는지는 코드가 수행하는 작업에 달려 있다는 것입니다.

나는 그들이 자주 발생할 수 있다고 예상 할 때 (예를 들어 사용자가 피각 데이터를 입력하는 경우) 확인 된 예외를 던지고 호출 코드가 상황을 처리 할 것으로 기대합니다.

호출 코드가 처리 할 것으로 예상되지 않는 드문 상황이 발생하면 확인되지 않은 / 런타임 예외 (확인되지 ​​않은 횟수만큼)가 발생합니다. 예를 들어 결코 예상하지 못한 이상한 메모리 관련 오류가있을 수 있습니다. 응용 프로그램을 중단시킬 것으로 예상되는 종류의 오류는 확인되지 않습니다.

어느 정도의 지원 없이는 사용자 앞에 예외가 나타나지 않아야합니다. "이 오류 덤프를 잘라내어 전자 메일에 붙여 넣으십시오"인 경우에도 마찬가지입니다. 오류가 있다는 말보다 사용자에게 더 성가신 것은 없지만 문제를 해결하기 위해 취할 수있는 세부 사항이나 조치가 제공되지 않습니다.

내 생각 엔 당신이 언급 한 철학은 다음 두 가지 소스 중 하나에서 비롯된 것입니다.

  • 게으른 프로그래머는 일을 피하려고합니다.
  • 또는 다른 방식으로 진행된 코드를 지원해야하는 개발자입니다. 즉, 과오 처리. 많은 양의 예외 처리가 포함 된 일종의 코드는 흐름 제어 및 기타 잘못된 목적으로 사용됩니다.

무언가가 자주 일어날 수 있다면 예외는 아닙니다. 그러나 사용자가 전혀 알지 못하는 오류가 발생해서는 안된다는 데 동의했습니다.
Manoj R

나는 당신의 철학에 동의합니다. 사용자를 위해 개발중인 응용 프로그램에서 런타임 예외가 발생해야하는 것은 무엇입니까?
randominstanceOfLivingThing

또한 런타임 예외가 발생하더라도 @assylias가 가리키는 규칙을 선호합니다.
randominstanceOfLivingThing

1

확인되지 않은 런타임 예외를 원하지 않으면 왜 java를 사용하고 있습니까? NullPointerException, ArithmeticException, ArrayIndexOutOfBounds 예외 등 거의 모든 곳에서 런타임 예외가 발생할 가능성이 있습니다.

예를 들어 SAP NetWeaver 설치와 같은 일부 J2EE 시스템의 로그 파일을 한 번 읽으면 이러한 예외가 문자 그대로 항상 발생한다는 것을 알 수 있습니다.


Java 언어 사양에서 : "런타임 예외 클래스 (RuntimeException 및 해당 서브 클래스)는 Java 프로그래밍 언어 디자이너의 판단에 따라 이러한 예외를 선언해야 정확성을 설정하는 데 크게 도움이되지 않기 때문에 컴파일 타임 검사에서 제외됩니다. Java 프로그래밍 언어의 많은 조작 및 구성으로 인해 런타임 예외가 발생할 수 있습니다. "
randominstanceOfLivingThing

1
Java 런타임 시스템에는 특정 호출을 수행하려는 이유에 대한 단서가 없으므로 Java에서 발생하는 런타임 예외입니다. 예 : null 인 메소드를 호출하면 NullPointerException이 발생합니다. 이 경우 Java 런타임 시스템에는 프로그래머에게 어리석은 단어가 없으며 NullPointerException으로 호출자를 때립니다. 슬픈 부분은 발신자가 Netweaver 제품을 귀하에게 판매했으며 사용자로서 귀하는 이제 프로그래밍 불량의 희생자라는 것입니다. 테스터는 모든 경계 테스트를 수행하지 않았으므로 동일하게 책임을 져야합니다.
randominstanceOfLivingThing

1

예외 처리에 대한 몇 가지 규칙이 있습니다. 그러나 먼저 예외는 코드에 의해 노출되는 인터페이스의 일부 라는 것을 기억해야 합니다. 문서화하십시오 . 인터페이스가 공개 인터페이스 일 때 특히 중요하지만 개인 인터페이스에서도 매우 좋습니다.

예외는 코드가 적절한 작업을 수행 할 수있는 지점에서만 처리해야합니다. 최악의 처리 옵션은 그들에 대해 전혀 아무것도하지 않는 것입니다. 정확히 올바른 옵션 일 때만 수행해야합니다. (내 코드에서 그러한 상황이 발생하면 그 효과에 대한 주석을 포함하여 빈 몸에 대해 걱정하지 않아도됩니다.)

두 번째로 최악의 옵션은 원본을 원인으로 첨부하지 않고 관련이없는 예외를 발생시키는 것입니다. 여기서 문제는 문제의 진단을 허용하는 원래 예외 내의 정보가 손실된다는 것입니다. 당신이 아무도와 아무것도 할 수 없다는 것을 만드는 (다른 우리가 증오하는 방법 "그렇지 않은 일", 그리고 우리 모두가 알고 불평보다 버그 리포트를).

예외를 기록하는 것이 훨씬 좋습니다. 이를 통해 누군가가 문제점을 찾아서 해결할 수 있지만 외부 연결을 통해 문제점이 유실되거나보고 될 때만 예외를 기록해야합니다. 로깅이 더 자주 중요한 문제가 아니기 때문에 과도한 로깅은 더 많은 정보를 포함하지 않고 더 많은 공간을 소비하는 로그를 의미하기 때문입니다. 예외를 기록한 후에 는 짧은 버전을 일치시킬 수 있도록 보고서에 생성 시간 또는 기타 상관 관계 식별자가 포함되어있는 한 양심을 가지고 사용자 / 클라이언트 에게 précis 를보고 할 수 있습니다. 필요한 경우 세부 사항을 확인하십시오).

물론 최선의 선택은 예외 상황을 완전히 처리하고 오류 상황을 전체적으로 처리하는 것입니다. 이 작업을 수행 할 수 있으면 반드시 수행하십시오! 예외를 기록하지 않아도된다는 의미 일 수도 있습니다.

예외를 처리하는 한 가지 방법은 문제에 대한 높은 수준의 설명을 제공하는 다른 예외를 발생시키는 것입니다 (예 : " failed to initialize"대신 " index out of bounds"). 예외의 원인에 대한 정보를 잃지 않는 한 좋은 패턴입니다. cause상위 예외를 초기화 하거나 위에서 설명한대로 세부 사항을 기록하려면 세부 예외를 사용하십시오 . 로깅은 IPC 호출과 같은 프로세스 간 경계를 넘을 때 가장 적합합니다. 연결의 다른 쪽 끝에는 하위 수준 예외 클래스가 전혀 존재하지 않을 것입니다. 내부 경계를 넘을 때는 첨부 된 원인으로 유지하는 것이 가장 적합합니다.

또 다른 패턴은 catch-and-release입니다.

try {
    // ...
} catch (FooException e) {
    throw e;
}

이것은 다른 절 에서 유형 제한을 얻지 않는 한 안티 패턴 catch입니다. 즉, 예외를 그냥 내버려 둘 수는 없습니다. 그런 다음 Java의 추악한 기능입니다.

확인 된 예외와 확인되지 않은 예외는 메소드 경계를 넘는 확인 된 예외를 선언 해야 한다는 점 외에는 실제로 차이가 없습니다 . 확인되지 않은 예외를 @throwsjavadoc 주석 과 함께 문서화 하여 의도적으로 코드에 의해 처리되는 것을 알고 있으면 여전히 좋은 아이디어 입니다. java.lang.ErrorJVM 구현을 작성 하지 않는 한 의도적으로 또는 그 서브 클래스를 던지지 마십시오 .

의견 : 예기치 않은 오류 사례는 항상 코드의 버그를 나타냅니다. 확인 된 예외는 이러한 위협을 관리하는 방법이며 개발자가 오류 사례를 처리하는 데 어려움을 피하기 위해 의도적으로 확인되지 않은 예외를 사용하는 경우 시간을 정리해야하는 많은 기술적 부채가 발생합니다. 강력한 코드를 원한다면 조잡한 오류 처리는 전문적이지 않습니다 (그리고 오류 처리를 보는 것이 프로그래머가 실제로 얼마나 좋은지를 결정하는 좋은 방법입니다).


0

응용 프로그램을 복구 할 수있을 때만 확인 된 예외를 throw해야한다고 생각합니다. 따라서 라이브러리 사용자는 이러한 예외를 포착하고 복구해야하는 작업을 수행해야합니다. 다른 사항은 선택 해제해야합니다.

예를 들어,

앱이 파일 또는 데이터베이스에서 데이터를로드하는 경우 그때,..

try {
  File data = new File(...);
  // parse file here
} catch (Exception ex) {
  throw new MissingDataFileException("data file not found");
}

호출자는 항상 확인 된 MissingDataFileException을 발견 한 후 데이터베이스에서 데이터를로드하려고 시도 할 수 있습니다.

try {
  Connection con = DriverManager.getConnection( host, username, password );
  // query data here
} catch (Exception ex) {
  throw new RuntimeException("better call Saul!");
}

1
사울은 3 년 전에 자동차 사고로 사망했습니다. 불합격! ;-)
Donal Fellows
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.