斷言是 Java 1.4 引入的除錯輔助機制,允許開發者在代碼中聲明「此處必為真」的假設。本文詳細解析 assert 語法、啟用/停用方式、適用場景與濫用風險,助你正確使用這把雙刃劍。
// 形式 1:簡單斷言
assert booleanExpression;
// 形式 2:帶詳細訊息(斷言失敗時拋出 AssertionError,訊息為 detailExpression.toString())
assert booleanExpression : detailExpression;
booleanExpression:預期為 true 的布林表達式。detailExpression:任意表達式(基本型別、物件、方法呼叫),用於診斷上下文。預設關閉,生產環境零性能損耗。
| 操作 | 命令參數 | 範例 |
|---|---|---|
| 啟用所有類 | -ea 或 -enableassertions | java -ea MyApp |
| 停用所有類 | -da 或 -disableassertions | java -da MyApp |
| 啟用特定類 | -ea:ClassName | java -ea:com.demo.Service MyApp |
| 啟用特定套件及子套件 | -ea:pkg... | java -ea:com.demo... MyApp |
| 停用系統類 | -dsa / -esa | java -esa -da MyApp (啟用系統類,停用應用類) |
編譯:JDK 1.4+ 預設支援,無需特別參數。舊版需 javac -source 1.4。
public void setAge(int age) {
assert age > 0 && age < 150 : "非法年齡: " + age; // 失敗拋出 AssertionError
this.age = age;
}
true:繼續執行,零開銷。false:拋出 java.lang.AssertionError(Error 子類,**不可捕捉恢復**,導致執行緒終止)。detailExpression 只在失敗時求值,避免副作用。default 分支理論不可達、switch 窮盡檢查。IllegalArgumentException)而非 AssertionError。assert list.remove(x) — 關閉斷言後副作用消失,行為不一致。| 維度 | assert | 拋出異常 | Logging |
|---|---|---|---|
| 生產環境行為 | 預設關閉,無開銷 | 始終執行,有開銷 | 由級別控制 |
| 失敗後果 | 拋出 Error,通常終止程式 | 可捕捉處理、恢復或記錄 | 僅記錄,不中斷流程 |
| 用途 | 開發期自檢、文檔化假設 | 運行期錯誤處理、流程控制 | 審計、診斷、監控 |
| 訊息豐富度 | 有限(detailExpression) | 豐富(自訂異常攜帶上下文) | 極豐富(結構化日誌) |
NullPointerException/IndexOutOfBoundsException,始終生效。Assert.state(condition, msg),拋出 IllegalStateException/IllegalArgumentException,適合業務驗證。assert 是開發期的「安全網」,用於檢查**程式員認為不可能發生**的邏輯假設。切記:生產環境默認關閉,絕不可用於業務關鍵驗證或有副作用的表達式。現代專案優先使用 Objects.requireNonNull、Guava Preconditions 或自訂異常,獲得確定性的運行期保護。