整理 Effective Java 書中 Item 57: Minimize the scope of local variables 心得筆記

主旨

在 Java 裡,區域變數(local variables)應該只在真正需要的時候才宣告,並且讓它的「作用範圍」儘可能小。這樣做不僅能讓程式碼更清楚、易讀,也能有效降低 bug 發生的機率。

點出問題

有些人習慣在區塊(block)一開始就把所有變數宣告好,這是從 C 語言時代留下來的老習慣。但在 Java 裡,我們可以在任何合法語句出現的地方宣告變數,因此更應該在「第一次使用變數時」才宣告它。

為什麼這麼做比較好?

  • 少一點雜訊:讀程式時不用一開始就記住所有變數是什麼。
  • 降低出錯風險:變數作用範圍小,能避免在不該用的地方誤用。
  • 強化 IDE 幫助:一些錯誤能在編譯時被偵測出來,而不是執行後才發現。

範例:for 迴圈的好處

// 推薦寫法:for-each 迴圈
for (Element e : c) {
    doSomething(e);
}

或是需要 Iterator 的話:

// 傳統 for 迴圈(需要呼叫 iterator.remove() 時)
for (Iterator<Element> i = c.iterator(); i.hasNext(); ) {
    Element e = i.next();
    doSomething(e);
}

這樣的好處是,ei 的作用範圍就只侷限在迴圈中,離開就無法再用它,也就不容易因為複製貼上出錯。

錯誤範例(使用 while 迴圈):

Iterator<Element> i = c.iterator();
while (i.hasNext()) {
    doSomething(i.next());
}

// 這邊用了新的變數 i2,但錯用了 i
Iterator<Element> i2 = c2.iterator();
while (i.hasNext()) {  // 錯誤!應該是 i2.hasNext()
    doSomethingElse(i2.next());
}

上面的程式碼會 compile 也會執行,但會做錯事,因為第一個 i 還在作用範圍內。

如果你用的是 for 迴圈:

for (Iterator<Element> i = c.iterator(); i.hasNext(); ) {
    ...
}

// 這邊 i 不在作用範圍內,若寫錯會直接 compile error
for (Iterator<Element> i2 = c2.iterator(); i.hasNext(); ) { // 編譯錯誤!
    ...
}

這正是我們要的保護機制。

小技巧:for 裡一次宣告多個變數

for (int i = 0, n = expensiveComputation(); i < n; i++) {
    // 使用 i,但避免每次都重新呼叫 expensiveComputation()
}

這樣做不但有效率,也讓 n 的作用範圍控制在迴圈內,不會留下多餘的變數污染區塊。

小節

縮小區域變數的作用範圍是乾淨、安全的程式設計好習慣:

  • 在哪裡用,就在哪裡宣告
  • 盡量使用 for-each 或傳統 for 來控制變數作用範圍
  • 不夠資訊不能初始化時就延後宣告
  • 變數範圍小,IDE 抓 bug 更精準
  • 如果一個方法太多變數混在一起,可能代表該拆成多個小方法了。

這些原則乍看簡單,但長期下來會讓程式更乾淨、更容易維護。