首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 代碼常見錯誤深度解析(二):防禦性複製、new 檢查、equals 陷阱、原子性、finally 清理與雜湊碼契約

     編輯:Java 相關知識

錯誤 5:防禦性複製不完整

回傳可變內部狀態時,僅複製容器(陣列/集合)而未複製元素物件,導致呼叫端可修改內部元素。

// 錯誤:僅 clone 陣列,Dimension 元素共享
public Dimension[] getValues() { return (Dimension[]) d.clone(); }

// 正確:深層複製元素
public Dimension[] getValues() {
    Dimension[] copy = (Dimension[]) d.clone();
    for (int i = 0; i < copy.length; i++)
        if (d[i] != null) copy[i] = new Dimension(d[i].height, d[i].width);
    return copy;
}

多維基本型別陣列同理:int[][] 需逐列 clone()。

錯誤 6:檢查 new 回傳是否為 null

Integer i = new Integer(400);
if (i == null) throw new NullPointerException(); // 無意義

Java new 失敗拋出 OutOfMemoryError,不會回傳 null。此檢查源自 C/C++ malloc/new 習慣,Java 中純屬多餘。

錯誤 7:用 == 代替 equals()

  • 基本型別:只能用 ==。
  • 物件:== 比較參考位址;equals() 比較邏輯內容(String、Integer 等已正確覆寫)。
  • 預設 Object.equals() 同 ==,故自訂類別必須覆寫 equals()。

錯誤 8:混淆原子與非原子操作

Java 保證 32 位元以下讀寫為原子(無需同步)。但 ++value 屬「讀-改-寫」三步驟,非原子,多執行緒下會競爭。

// 非執行緒安全
public void increment() { ++value; }

// 正確:同步
public synchronized void increment() { ++value; }

測試難重現,上線後在特定 JVM/CPU 才暴露,開發初期即正確同步。

錯誤 9:在 catch 區塊清理資源

// 錯誤:重複 close、漏捕 Error、close 可能拋出異常
try { os = new OutputStream(); ... os.close(); }
catch (Exception e) { if (os != null) os.close(); }

// 正確:finally 區塊保證執行
try { os = new OutputStream(); ... }
finally { if (os != null) try { os.close(); } catch (IOException ignored) {} }

finally 涵蓋正常返回、異常、Error 三種情況;close() 另套 try-catch 避免掩蓋原始異常。

錯誤 10:不必要的 catch 區塊

// 多餘:捕獲後立即重拋
try { ... } catch (Exception e) { throw e; } finally { cleanup(); }

// 精簡:直接 finally
try { ... } finally { cleanup(); }

Java 有 finally,不需強制配對 catch。僅在需處理/包裝異常時才寫 catch。

錯誤 11:未正確實作 equals/hashCode/clone

  • 父類覆寫上述方法 → 子類通常也需覆寫並保持契約:equals 對稱/傳遞/一致,hashCode 與 equals 一致,clone 深層複製。
  • 代碼審查時必檢查繼承鏈上的契約遵循情況。

總結

這 11 類錯誤在代碼審查中高頻出現。建立檢查清單、養成自審習慣,能大幅減少除錯時間,提升代碼健壯度。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved