@SneakyThrows
大膽地拋出之前從未有人拋出過的受檢異常!
概觀
@SneakyThrows
可以用來偷偷地拋出受檢異常,而無需在您方法的 throws
子句中實際宣告。 這個有些爭議的功能當然應該謹慎使用。 lombok 生成的程式碼不會忽略、包裝、替換或以其他方式修改拋出的受檢異常; 它只是欺騙了編譯器。 在 JVM (類別檔案) 層級,所有異常,無論是否受檢,都可以拋出,而無需考慮您方法的 throws
子句,這就是它能運作的原因。
當您想要選擇不使用受檢異常機制時,常見的使用案例主要圍繞在以下兩種情況
- 不必要的嚴格介面,例如
Runnable
- 無論什麼異常從您的run()
方法中傳播出來,無論是否受檢,它都會被傳遞到Thread
的未處理異常處理程序。 捕獲受檢異常並將其包裝在某種類型的RuntimeException
中只會模糊問題的真正原因。 - 一個「不可能」的異常。 例如,
new String(someByteArray, "UTF-8");
宣告它可以拋出UnsupportedEncodingException
,但根據 JVM 規範,UTF-8 必須 始終可用。 此處的UnsupportedEncodingException
與您使用 String 物件時的ClassNotFoundError
一樣不可能發生,而您也不會捕獲後者!
當使用 lambda 語法 (arg -> action
) 時,受到不必要的嚴格介面約束尤其常見; 然而,lambda 無法被註解,這意味著在 lambda 中使用 @SneakyThrows
並不容易。
請注意,不可能 直接捕獲偷偷拋出的受檢類型,因為 javac 不允許您為 try 區塊中沒有方法呼叫宣告為拋出的異常類型編寫 catch 區塊。 這個問題與上面列出的任何使用案例都不相關,因此請將此作為警告,您不應在沒有經過深思熟慮的情況下使用 @SneakyThrows
機制!
您可以將任意數量的異常傳遞給 @SneakyThrows
註解。 如果您不傳遞任何異常,您可以偷偷地拋出任何異常。
使用 Lombok
import lombok.SneakyThrows;
|
原生 Java
import lombok.Lombok;
|
支援的配置鍵
-
lombok.sneakyThrows.flagUsage
= [warning
|error
] (預設值:未設定) - 如果已配置,Lombok 會將任何
@SneakyThrows
的使用標記為警告或錯誤。
細則
由於 @SneakyThrows
是一個實作細節,而不是您方法簽名的一部分,因此,如果您嘗試宣告受檢異常為偷偷拋出,但您沒有呼叫任何拋出此異常的方法,則會發生錯誤。 (這樣做對於 throws
語句來說是完全合法的,以適應子類別)。 同樣地,@SneakyThrows
不會繼承。
對於人群中唱反調的人:Eclipse 在預設情況下會為未捕獲的異常提供「快速修復」,該修復會將有問題的語句包裝在 try/catch 區塊中,且 catch 區塊中只有 e.printStackTrace()
。 與僅僅偷偷地將異常繼續拋出相比,這是非常沒有效率的,以至於 Roel 和 Reinier 認為他們有充分的理由聲稱受檢異常系統遠非完美,因此有必要採用選擇退出的機制。
如果您在建構子上放置 @SneakyThrows
,則對同級或父級建構子的任何呼叫都將排除在 @SneakyThrows
處理之外。 這是我們無法解決的 java 限制:對同級/父級建構子的呼叫必須是建構子中的第一個語句; 它們不能放在 try/catch 區塊內。
在空方法上,或在為空或僅呼叫同級/父級建構子的建構子上使用 @SneakyThrows
會導致沒有 try/catch 區塊並產生警告。