給定一個可能拋出的函數:public static int f() throws Exception { // do something}這段代碼有什么辦法:public static int catchF() throws Exception { try { return f(); } catch (Exception ex) { throw ex; }}和直接打電話有什么不同嗎f?即調用者可以通過檢查異常來檢測差異嗎?catchF使用而不是有任何明顯的開銷嗎f?如果沒有區別,編譯器或 JVM 能否將對的調用優化catchF為對的直接調用f?雖然這看起來像是一件奇怪的事情,但用例是在先前隱藏異常之后在類型級別重新引入異常:class Test { // Hide the exception. public static <X extends Exception, T> T throwUnchecked(Exception ex) throws X { throw (X) ex; } // Interface for functions which throw. interface Throws<T, R, X extends Exception> { R apply(T t) throws X; } // Convert a function which throws a visible exception into one that throws a hidden exception. public static <T, R, X extends Exception> Function<T, R> wrap(Throws<T, R, X> thrower) { return t -> { try { return thrower.apply(t); } catch(Exception ex) { return throwUnchecked(ex); } }; } // Unhide an exception. public static <R, X extends Exception> R unwrap(Supplier<R> supp) throws X { try { return supp.get(); } catch (Exception ex) { throw (X)ex; } } public static Stream<Integer> test(Stream<String> ss) throws NumberFormatException { return Test.<Stream<Integer>, NumberFormatException>unwrap( () -> ss.map(wrap(Integer::parseInt)) ); } public static void main(String[] args) throws NumberFormatException { final List<Integer> li = test(Arrays.stream(new String[]{"1", "2", "3"})).collect(toList()); System.out.println(li); }}目的是將拋出異常的函數包裝到在類型級別隱藏異常的函數中。這使得異??捎糜诶缌?。
2 回答

皈依舞
TA貢獻1851條經驗 獲得超3個贊
與直接調用 f 有什么不同嗎?
不。
即調用者可以通過檢查異常來檢測差異嗎?
不,因為此時您沒有構造新的異常。堆棧跟蹤是在調用的位置構建的new WhateverException(...)
(不是在調用位置的位置throw
,盡管它們通常位于同一位置)。
通常,如果由于異常而需要進行一些清理,則可以重新拋出捕獲的異常:
try {
? // ...
} catch (SomeException e) {
? // Clean up resources.
? throw e;
}
調用堆棧展開時發生的事情對調用者來說既不可見也不相關。
快速演示可以顯示堆棧跟蹤是相同的,無論異常是被捕獲并重新拋出還是僅僅允許傳播。
使用 catchF 而不是 f 是否有任何明顯的開銷?
構造異常的開銷將遠遠超過此冗余構造的任何開銷。

ibeautiful
TA貢獻1993條經驗 獲得超6個贊
簡單地重新拋出并且不影響異常的已知類型的異常處理程序絕對沒有語義效果。
那么,理論上,編譯器或 JVM 可以優化 try-catch out。在實踐中,我懷疑他們這樣做,因為這樣的代碼應該很少見并且不在熱路徑上(永遠不應該有例外);實現這樣的優化可能不值得付出努力。
添加回答
舉報
0/150
提交
取消