2015-01-12 63 views
6

有了下面的代碼,如何從外部塊重新拋出lambda塊中的異常?

void key(Key) throws SomeCheckedException { 
} 

void supplier(Supplier<Key> s) throws SomeCheckedException { 
    ofNullable(s).ifPresent(s -> {     // | 
     try {          // | 
      key(s.get());       // | 
     } catch (final SomeCheckedException sce) { // | 
      // sce is coming from key() method  // | 
      // How can I throw sce for outer method? // --/ 
     } 
    }); 
} 

我怎麼能扔sce彷彿方法(supplier)方法把它扔?

請注意,上面的代碼只是一個例子。我需要key(s.get())在一個lambda表達式中。

void supplier(Supplier<Key> s) throws SomeCheckException { 
    key(s.get()); 
} 
+2

啊,我沒有想到'鍵(...)'可能會拋出檢查異常。但[我的答案](http://stackoverflow.com/a/27900544/2711488)也處理這種情況。 – Holger

回答

2

如果您想以安全的方式處理已檢查的異常,則需要一個輔助方法,該方法提供將異常打包爲子類型RuntimeException的功能。下面是這樣的,它使用通用的類型安全,以確保只有聲明異常的一個輔助功能將被重新拋出(除非您使用不安全的操作):

public static <E extends Throwable> void attempt(
    Consumer<Function<E,RuntimeException>> action) throws E { 

    final class CarryException extends RuntimeException { 
     final E carried; 
     CarryException(E cause) { 
      super(cause); 
      carried=cause; 
     } 
    } 

    try { action.accept(CarryException::new); } 
    catch(CarryException ex) { throw ex.carried; } 
} 

它支持任意action將接收一個函數,它不將檢查的異常類型臨時包裝到RuntimeException。這個包裝將是透明的,方法attempt將正常完成或拋出原始的檢查異常E(或一個不相關的未經檢查的異常,如果發生)。

所以你可以使用它像這樣:

public static void processIterm(Supplier<Key> s) 
    throws SomeCheckedException { 

    attempt((Function<SomeCheckedException, RuntimeException> thrower) -> 
     Optional.ofNullable(s).ifPresent(nonNull -> { 
      try { key(nonNull.get()); } // assuming key may throw SomeCheckedException 
      catch(SomeCheckedException e) { throw thrower.apply(e); } 
     })); 
} 

由於嵌套操作的編譯器無法推斷出異常自動型。上面的代碼使用參數類型的明確聲明(thrower)。或者你可以使用類型調用的幫助方法,如

ContainingClass.<SomeCheckedException>attempt(thrower -> 
    Optional.ofNullable(s).ifPresent(nonNull -> { 
     try { key(nonNull.get()); } 
     catch(SomeCheckedException e) { throw thrower.apply(e); } 
    })); 
7

你不行。 Supplier#get()沒有聲明拋出任何(檢查)的異常。請記住,lambda表達式只是簡單地創建一個實例,並不實際調用目標函數接口方法。

如果你想,你可以將檢查的異常包裝在一個未經檢查的異常中並拋出異常。