在 Java 中,類別成員變數 (欄位) 若未顯式初始化,會獲得預設值 (null, 0, false 等)。但 方法區域變數 (區域變數) **沒有預設值**,必須在第一次讀取前顯式賦值,否則編譯錯誤:variable might not have been initialized。
FileInputStream in = null;?FileInputStream in = null; // 1. 顯式初始化為 null,滿足「確定賦值」分析
try {
in = new FileInputStream(file); // 2. 可能拋出 FileNotFoundException
// 讀取操作...
} catch (IOException e) {
// 處理異常...
} finally {
if (in != null) { // 3. 安全關閉:in 可能仍為 null (new 失敗時)
try { in.close(); } catch (IOException ignored) {}
}
}
三大理由:
new FileInputStream() 可能拋出異常導致賦值不執行,編譯器無法保證 in 在 finally 區塊已被賦值,故要求先初始化。finally 區塊無論如何都會執行,若 in 未初始化直接判斷 in != null 會編譯錯誤;初始化為 null 後,new 失敗時 in 保持 null,close() 不會被呼叫,避免 NullPointerException。try 區塊內宣告的變數在 finally 不可見,必須在 try 外宣告。// 編譯器自動生成 finally 關閉邏輯,無需手動 null 檢查,變數作用域自動限制在 try 區塊
try (FileInputStream in = new FileInputStream(file);
BufferedInputStream bin = new BufferedInputStream(in)) {
// 讀取操作...
} catch (IOException e) {
// 處理異常...
}
AutoCloseable 的資源皆適用。close() 拋出的異常會被附加在主要異常的 Suppressed 列表中,不遺失資訊。int x; // 錯誤:未初始化
int y = 0; // 正確:顯式初始化
System.out.println(y);
Eclipse/IntelliJ 會即時提示 The local variable x may not have been initialized,這是編譯器保護開發者免受「使用未初始化記憶體」未定義行為的體現 (C/C++ 允許但危險)。
區域變數必須顯式初始化 是 Java 語言設計為「安全優於便利」的核心體現。IO 流舊式寫法 Type var = null; 是為了滿足編譯器確定賦值分析與 finally 安全關閉的雙重需求;現代開發請直接使用 try-with-resources,消除樣板碼、避免資源洩漏、程式碼更簡潔。