34

나는 다음 코드를 여러 번 본 적이있다.

try
{
    ... // some code
}
catch (Exception ex)
{
    ... // Do something
    throw new CustomException(ex);

    // or
    // throw;

    // or
    // throw ex;
}

예외를 다시 던지는 목적을 설명해 주시겠습니까? 예외 처리에서 패턴 / 모범 사례를 따르고 있습니까? (나는 "Caller Inform"패턴이라고 불리는 곳을 읽었습니다.)

13 답변


38

같은 예외를 되 돌리는 것은 예외를 기록하고 싶지만 처리 할 수 없다면 유용합니다.

잡힌 예외를 래핑하는 새로운 예외를 던지면 추상화에 유리합니다. 예를 들어 라이브러리에 라이브러리 클라이언트가 알지 못하는 예외를 throw하는 제 3 자 라이브러리가 사용됩니다. 이 경우 라이브러리의 고유 한 예외 유형으로 래핑하고이를 대신 throw합니다.


  • 내가 이해 했는가? 다시 던진 예외를 처리 할 필요가 없다. - chester89
  • 즉, 예외를 처리 할 수없는 코드가있는 경우 (즉, 호출자가 대신 처리하도록하려는 경우) 두 가지 선택을 할 수 있습니다. 1. catch하지 않습니다. ; 2. 그것을 잡아서 어딘가에 기록한 다음 다시 던지십시오. 재실행함으로써, 그것은 마치 전혀 잡히지 않은 것처럼 발신자에게 나타납니다. - Chris Jester-Young

24

실제로는 차이가 있습니다.

throw new CustomException(ex);

throw;

두 번째는 스택 정보를 보존합니다.

그러나 때로는 예외를 응용 프로그램 도메인에 "친숙하게"만들려고하면 DatabaseException이 GUI에 도달하는 대신 원래의 예외가 포함 된 사용자 정의 예외가 발생합니다.

예를 들면 :

try
{

}
catch (SqlException ex)
{
    switch  (ex.Number) {
        case 17:
        case 4060:
        case 18456:
           throw new InvalidDatabaseConnectionException("The database does not exists or cannot be reached using the supplied connection settings.", ex);
        case 547:
            throw new CouldNotDeleteException("There is a another object still using this object, therefore it cannot be deleted.", ex);
        default:
            throw new UnexpectedDatabaseErrorException("There was an unexpected error from the database.", ex);
    } 
}


  • & quot; 자신 & quot; 사람들이 실제로 오류 메시지를 알지 못합니까? 오류가 발생했습니다. :-피 - Chris Jester-Young
  • 죄송합니다. D이 바로 ... (영어 실력이 떨어졌습니다 : D) - Davy Landman
  • 귀하의 첫 번째 진술은 오해의 소지가 있습니다. throws new CustomException (ex) 스택 정보를 잃어 버리지는 않지만, CustomException 객체의 InnerException에 보존됩니다. 당신이 예전을 던질 때입니다; 스택이 손실되었음을 나타냅니다. - Matt Howells
  • 원래의 예외에서 볼 수있는 스택 추적은 자신의 캐치에서 시작됩니다. 예, 예외의 실제 시작에 대해 InnerException을 계속 확인할 수 있지만 직접 조각을 넣어야합니다. 던짐은 스택과 완전한 "경로"를 유지할 것이다. 남아있을거야. - Davy Landman
  • @davy - ToString 구현에는 innerexception의 ToString도 포함되어 있으므로 일반적으로 손실되지 않습니다. 대부분의 .Net 프레임 워크 예외는이 관례를 따릅니다. (다만 방금 ServiceModel.FaultException을 발견했지만 - 그럴 수는 없습니다.) 유일한 문제는 .ToString을 로깅해야한다는 것입니다. 그것은 우수 사례이지만, 나는 그런 내용으로 공개되는 경우는 드물다. - FastAl

10

때로는 메소드의 구현 세부 사항을 숨기거나 개선하려는 경우가 있습니다. 문제의 추상화 수준으로 인해 호출자에게 더 의미가 있습니다. 방법의. 이렇게하려면 원래 예외를 가로 챌 수 있고 대체 할 수 있습니다. 문제를 설명하는 데 더 적합한 맞춤 예외입니다.

예를 들어 텍스트 파일에서 요청한 사용자의 세부 정보를로드하는 메소드를 예로 들어 보겠습니다. 이 방법은 사용자 ID와 접미사 ".data"로 이름 지정된 텍스트 파일이 있다고 가정합니다. 이 파일이 실제로 존재하지 않으면 각 사용자의 세부 정보가 텍스트 파일에 저장된다는 사실이 메서드의 구현 세부 사항이기 때문에 FileNotFoundException을 throw하는 것은별로 의미가 없습니다. 따라서이 메서드는 설명 메시지를 사용하여 사용자 지정 예외에서 원래 예외를 래핑 할 수 있습니다.

표시된 코드와 달리 가장 좋은 방법은 원래 예외를 새 예외의 InnerException 속성으로로드하여 유지해야한다는 것입니다. 이는 개발자가 필요한 경우 기본 문제를 계속 분석 할 수 있음을 의미합니다.

맞춤 예외를 만들 때 다음과 같은 유용한 체크리스트가 있습니다.

• 예외가 던진 이유를 나타내는 좋은 이름을 찾아 이름이 "Exception"이라는 단어로 끝나는 지 확인하십시오.

• 세 가지 표준 예외 생성자를 구현해야합니다.

• Serializable 특성으로 예외를 표시했는지 확인하십시오.

• deserialization 생성자를 구현해야합니다.

• 개발자가 예외를 더 잘 이해하고 처리하는 데 도움이되는 사용자 지정 예외 속성을 추가합니다.

• 사용자 지정 속성을 추가하는 경우 GetObjectData를 구현하고 재정 의하여 사용자 지정 속성을 serialize해야합니다.

• 사용자 지정 속성을 추가하는 경우 Message 속성을 재정 의하여 표준 예외 메시지에 속성을 추가 할 수 있습니다.

• 사용자 지정 예외의 InnerException 속성을 사용하여 원래 예외를 첨부해야합니다.


8

일반적으로 응용 프로그램 내에서 코드가 구조적으로 어디에 위치하는지에 따라 두 가지 이유 중 하나를 잡아서 다시 throw합니다.

응용 프로그램의 핵심에서는 예외를 더 의미있는 것으로 변환하기 위해 일반적으로 catch하고 다시 throw합니다. 예를 들어 데이터 액세스 계층을 작성하고 SQL Server에서 사용자 정의 오류 코드를 사용하는 경우 SqlException을 ObjectNotFoundException과 같은 것으로 변환 할 수 있습니다. 이는 (a) 호출자가 특정 유형의 예외를 쉽게 처리 할 수 있고 (b) 다른 계층에 지속성을 위해 SQL Server를 사용하고 있다는 사실과 같은 계층의 구현 세부 사항을 방지하기 때문에 유용합니다. 미래의 일들을보다 쉽게 변경할 수 있습니다.

응용 프로그램의 경계에서 예외를 번역하지 않고 catch하고 다시 throw하는 것이 일반적이므로 디버깅 및 라이브 문제 진단에 도움이됩니다. 이상적으로는 운영 팀이 쉽게 모니터링 할 수있는 오류 (예 : 이벤트 로그)뿐만 아니라 개발자를위한 제어 흐름에서 예외가 발생한 곳 (일반적으로 추적)에 대한 컨텍스트를 제공하는 어딘가에서 오류를 게시하는 것이 이상적입니다.


2

나는 다음과 같은 이유들을 생각할 수있다.

  • 호출자가 고정 된 예외 집합에 대해서만 염려 할 수 있도록 API의 일부로 던진 예외 유형 세트를 고정 된 상태로 유지합니다. 자바에서는 체크 된 예외 메커니즘으로 인해 실제로 그렇게해야합니다.

  • 예외에 컨텍스트 정보를 추가합니다. 예를 들어 DB에서 맨손으로 "레코드를 찾을 수 없음"을 전달하는 대신이를 포착하고 "... YYY 제품을 찾는 주문 번호 XXX을 처리하는 중"을 추가 할 수 있습니다.

  • 일부 정리 작업 - 파일 닫기, 트랜잭션 롤백, 일부 핸들 해제.


1

일반적으로 "Do Something"은 예외를 더 잘 설명하고 (예를 들어 다른 예외로 감싸는 경우) 또는 특정 소스를 통해 정보를 추적합니다.

또 다른 가능성은 예외 유형이 예외를 포착해야하는지 알 수있는 정보가 충분하지 않은 경우입니다.이 경우 예외를 포착하면 자세한 정보가 제공됩니다.

이것은 메소드가 순전히 좋은 이유로 사용되었다는 것을 말하는 것은 아니며 개발자가 추후 정보가 필요할 수도 있다고 생각할 때 사용됩니다.이 경우 try {} catch {throw;} 스타일이 사용됩니다. 별로 도움이 안된다.


1

나는 그것이 당신이 예외로 무엇을하려고하는지에 달려 있다고 생각한다.

하나의 좋은 이유는 catch에서 먼저 오류를 기록한 다음이를 UI에 던져 친숙한 오류 메시지를 생성하는 옵션을 사용하여 원래의 오류가 포함 된 오류의 "고급 / 세부 정보"보기를 더 많이 볼 수 있습니다 .

또 다른 접근법은 "재시도"접근법이다. 예를 들어, 에러 카운트가 유지되고, 재 시도의 일정량이 에러가 스택으로 보내지는 유일한 시간이다. (이것은 타임 아웃 데이터베이스 호출을위한 데이터베이스 액세스를 위해 때때로 수행된다. 느린 네트워크를 통한 웹 서비스 액세스).

그러나 그것을 할 다른 이유가있을 것입니다.


1

참고로, 이것은 각 유형의 재 드로잉과 관련된 질문입니다.예외를 throw하기위한 성능 고려 사항

내 질문은 "왜"우리는 응용 프로그램 예외 처리 전략에서 예외와 그 사용법을 다시 던집니까?


0

EntLib ExceptionBlock을 사용할 때까지는 오류를 로그하기 전에 오류를 로그하는 데 사용하고있었습니다. 그 시점에서 내가 처리 할 수 있다고 생각할 때 더 심술 스럽지만, 당시에는 플로우 - 온 (flow-on) 버그를 다루기보다는 UAT (로그를 기록한 후)에서 급히 실패하게하는 것이 낫습니다.


0

응용 프로그램은 아마도 호출 스택보다 높은 예외를 다시 잡아서 다시 던져서 상위 처리기가 해당 호출을 가로 채서 처리 할 수있게합니다. 애플리케이션이 expection을 기록하거나보고하는 최상위 예외 처리기를 갖는 것은 매우 일반적입니다.

또 다른 대안은 코더가 게으르다가 처리하려고하는 일련의 예외를 잡는 대신 모든 것을 포착 한 다음 실제로 처리 할 수없는 것만 다시 던져 버리는 것입니다.


0

Rafal이 말했듯이 검사 된 예외를 확인되지 않은 예외로 변환하거나 API에 더 적합한 확인 된 예외로 변환하기 위해 수행되는 경우가 있습니다. 여기에 예제가 있습니다.

http://radio-weblogs.com/0122027/stories/2003/04/01/JavasCheckedExceptionsWereAMistake.html


0

다음과 같이 예외를 살펴 본다면메소드 결과를 얻는 다른 방법, 예외를 다시 던지는 것은 다른 객체에 결과를 래핑하는 것과 같습니다.

그리고 이것은 비범 한 세계에서 일반적인 작업입니다. 일반적으로 이것은 두 개의 어플리케이션 레이어의 경계에서 발생합니다 - 레이어의 함수B레이어에서 함수를 호출합니다.C, 그것은 변형된다.C~에 대한 결과B내부 양식.

A -- calls --> B -- calls --> C

그렇지 않으면 레이어에서A레이어를 호출하는B처리 할 수있는 전체 JDK 예외 집합이있을 것입니다. :-)

허용 된 대답이 지적한대로 레이어A알지도 못하다.C예외예요.

A 층, servlet : 이미지와 메타 정보를 가져옵니다.

B 층, JPEG 라이브러리 : 사용 가능한 DCIM 태그를 수집하여 JPEG 파일을 구문 분석합니다.

레이어 C, 간단한 DB : 랜덤 액세스 파일에서 문자열 레코드를 읽는 클래스. 일부 바이트가 손상되어 " 'bibliographicCitation'레코드의 UTF-8 문자열을 읽을 수 없습니다. '라는 예외가 발생합니다.

그래서A'서지 인용'의 의미를 이해하지 못할 것이다. 그래서B이 예외를 번역해야합니다.A으로TagsReadingException원본을 래핑합니다.


-3

예외를 다시 던지는 주된 이유는 호출 스택을 손대지 않게하는 것입니다. 따라서 발생하는 상황을 자세히 파악하고 시퀀스를 호출 할 수 있습니다.

연결된 질문


관련된 질문

최근 질문