2009-10-30 2 views
11

(늦은 편집 :. 자바 7이 때문에 "final rethrow" featureseems like it will be added의, 때이 질문은 희망 폐기 될 예정입니다) 종종내 안전한 전복은 얼마나 안전한가요?


,이처럼 보이는 상황에서 자신을 찾을 :

C#에서
 
    do some initialization 
    try { 
     do some work 
    } catch any exception { 
     undo initialization 
     rethrow exception 
    } 

당신은 이런 식으로 작업을 수행 할 수 있습니다

InitializeStuff(); 
try 
{ 
    DoSomeWork(); 
} 
catch 
{ 
    UndoInitialize(); 
    throw; 
} 

Java의 경우에는 대체 할만한 것이 없으며 the proposal for improved exception handling was cut from Java 7 이후로 우리가 뭔가를 얻을 때까지 몇 년이 걸리는 것처럼 보입니다.

(편집 : :. 반 년 후, final rethrow is back가, 또는 그렇게 보인다)

public final class Rethrow { 

    private Rethrow() { throw new AssertionError("uninstantiable"); } 

    /** Rethrows t if it is an unchecked exception. */ 
    public static void unchecked(Throwable t) { 
     if (t instanceof Error) 
      throw (Error) t; 
     if (t instanceof RuntimeException) 
      throw (RuntimeException) t; 
    } 

    /** Rethrows t if it is an unchecked exception or an instance of E. */ 
    public static <E extends Exception> void instanceOrUnchecked(
      Class<E> exceptionClass, Throwable t) throws E, Error, 
      RuntimeException { 
     Rethrow.unchecked(t); 
     if (exceptionClass.isInstance(t)) 
      throw exceptionClass.cast(t); 
    } 

} 

일반적인 사용 :

public void doStuff() throws SomeException { 
    initializeStuff(); 
    try { 
     doSomeWork(); 
    } catch (Throwable t) { 
     undoInitialize(); 
     Rethrow.instanceOrUnchecked(SomeException.class, t); 
     // We shouldn't get past the above line as only unchecked or 
     // SomeException exceptions are thrown in the try block, but 
     // we don't want to risk swallowing an error, so: 
     throw new SomeException("Unexpected exception", t); 
    } 
    private void doSomeWork() throws SomeException { ... } 
} 

는 그것은이다 그래서 난 내 자신의 롤 결정 보통 Throwable을 붙잡는 것은 보통 눈살을 찌푸리게합니다. 나는 예외를 되돌리기 위해 반사를 사용하는 것에 정말로 만족하지 않습니다. 그리고 나는 항상 약간의 불안감을 느낍니다. "이것은 일어나지 않을 것입니다"라고 말하지만 실제로는 작동합니다. ell (또는 적어도 보인다). 내가 궁금해하는 것은 :

  1. 내 재사용 도우미 메서드에 결함이 있습니까? 내가 놓친 몇 가지 코너 사례가 있습니까? (나는 Throwable이 뭔가 심각한 것으로 인해 내 undoInitialize이 실패 할 수도 있지만, 괜찮다고 알고 있습니다.).
    • 누군가 이미 이것을 발명 했습니까? Commons Lang의 ExceptionUtils을 살펴 봤지만 다른 것들도 마찬가지입니다.

      편집

:

  • finally 내가 찾고 있어요 드로이드 없습니다. 나는 예외가 던져 질 때만 물건을 다루는 것에 관심이있다.
  • 예, 나는 잡기가 Throwable은 큰 노 - 아니,하지만 그것은 덜 악마 여기에 동일한 코드와 함께 세 catch 섹션 (Error, RuntimeExceptionSomeException 각각)에 비해 생각합니다.
  • 나는 오류를 억누르려고하지 않는다는 것을 알아 두십시오 - 아이디어는 try 블록에 던져진 예외가 몇 가지를 되 감아 자마자 호출 스택을 통해 거품을 일으키기 시작한다는 것입니다.
+1

Throwable 잡기에 대한 좋은 근거가 있습니다. 그것이 당신을 실망시키지 않도록하십시오. GOTO를 사용하는 것과 매우 흡사합니다. "사용하지 않으면 사용하지 마십시오." –

답변

5

여기에는 몇 가지 방법이 있습니다. 예외가 무엇인지 알 필요가 없으면 첫 번째는 내 취향입니다.

boolean okay = false; 
try { 
    // do some work which might throw an exception 
    okay = true; 
} finally { 
    if (!okay) // do some clean up. 
} 

은 경우에 따라 try 블록이 무엇에 따라 추가 변수없이 동일한 기능을 수행 할 수 있습니다.

두 번째 옵션은 해킹이지만 작동합니다.

try { 
    // do some work which might throw an exception 
} catch (Throwable t) { 
    // do something with t. 
    Thread.currentThread().stop(t); 
} 

정지 (Throwable를 t) 방법 대신에 검사되지 않은 방식으로 제공되는 예외를 발생하는 실 발생, 실을 멈추지 않는다.

Unsafe.throwException()을 약간의 재미를 보면서 사용할 수 있으며 잊어 버린 Generics로이를 수행 할 수있는 방법이 있습니다.

1

초기화가 필요하지 않다면 finally 블록에 코드를 넣는 것이 좋습니다. 어떤 시점에서 호출해야한다면 항상 정리해야합니다.

Throwable 내가 처리하고자하는 예외 중 일부로 catch하는 것을 신경 쓰지 않으며 일부는 사용자가 아무것도 수행 할 수없는 예외 (예 : NullPointerException)를 전달하는 용도로 사용되지 않습니다.

하지만, 당신이 SomeException는 다음과 같이 정의되어 있지만 OutOfMemoryException가 발생하는 경우, 당신 던질 수있는 그것을 잡을 것입니다 무엇을 보여주지 못했지만, SomeException 그래서 래퍼가 샘플 기능에 필요하므로이 같은 유형하지 않을 수 있습니다 , 적어도 내가 instanceOrUnchecked 메소드를 볼 때.

단위 테스트를 작성하고 다른 클래스의 예외를 시도하여 예상대로 작동하는지 또는 작동하지 않는지를 예상하여 예상되는 동작을 문서화 할 수 있습니다. 원인이 확인이 끝난 예외 인 경우에만

+0

'SomeException extends Exception'입니다. 'finally'에서 uninitializing에 관해서는 - 예외가 던져지면 초기화가 일어나기를 원합니다. 물론 불리언 ​​플래그를 false로 설정 한 다음 try 블록의 마지막 부분에 true로 설정하면되지만 약간 성가기는 마찬가지입니다. (누군가가 생각하지 않고 true로 설정된 후에 코드를 추가하면 어떨까요? 예외 처리?). – gustafc

+0

또한 테스트를 거쳤으며 잘 작동합니다 ... 생각할 수 있었던 모든 상황에서 코드 작성을 관리했음을 증명합니다. – gustafc

+1

예외를 확장하는 클래스가 아니라 Throwable을 확장하는 클래스로 테스트 했습니까? –

1

대안은 SomeException를 만드는 공장을하는 것입니다 :

public static SomeException throwException(String message, Throwable cause) throws SomeException { 
     unchecked(cause); //calls the method you defined in the question. 
     throw new SomeException(message, cause); 
    } 

클라이언트가 뭔가를 할 수 있도록 나는 방법에 반환 값에 넣어 이유는 이 같은 :

 catch (Throwable e) { 
     undoInitialize(); 
     throw SomeException.throwException("message", e); 
    } 

컴파일러는 방법은 반환 형식이있는 경우 catch 문 후 반환을 요구하지 않는 바보짓을하지만, 클라이언트가 호출하기 전에 던져 넣어 잊어 버린 경우 여전히 예외가 발생되도록 공장 방법에.

코드의 단점은 이식성이 낮다는 것입니다 (SomeException에서는 작동하지만 SomeOtherException에서는 작동하지 않음).하지만 필요한 모든 예외 유형에 해당하지 않기 때문에 괜찮을 수도 있습니다. 실행 취소가 초기화됩니다.

유스 케이스에 맞는 경우 확인되지 않은 호출을 SomeException의 생성자에 넣고 모든 하위 클래스에서 사용할 수있는 논리를 가질 수 있지만 특정 프로젝트에 맞아야합니다. 일반적으로 좋은 생각이 아닙니다. 이 경우 런타임 예외를 래핑하지 못하게됩니다.

 public SomeException(message, cause) { 
      super(message, unchecked(cause)); 
     } 

     private static Throwable unchecked(Throwable cause) { 
      if (cause instanceof Error) throw (Error) cause; 
      if (cause instanceof RuntimeException) throw (RuntimeException) cause; 
      return cause; 
     } 
+0

팩토리 함수는 좋지만, 예외 클래스 (SomeException을 확장하는 여러 클래스)가 있기 때문에 좀 더 유연해야합니다. 나는 두 번째 대안의 영리함을 좋아하지만, 아마도 너무 영리하다고 생각합니다. 유지 보수 프로그래머를위한 WTF 잠재력이 높은 것 같습니다. – gustafc

관련 문제