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

Java 代碼診斷:Run-On Initialization 錯誤模式——構造函數不完整的禍端

     編輯:Java 相關知識

什麼是 Run-On Initialization?

當類的構造函數未初始化所有字段,強制客戶代碼在構造後連續調用多個 setter 完成初始化,這種多步驟初始化稱為 Run-On Initialization。它極易導致:異常拋出時字段未初始化、初始化步驟遺漏/順序錯誤、類演進導致所有客戶代碼需同步修改(Rogue Tile 模式)。

典型症狀:異常中斷留下半初始化對象

RestrictedInt ri = new RestrictedInt(false);
ri.setValue(0); // 拋出 CantTakeZeroException,value 字段仍為 null
// 異常處理器訪問 ri.value → NPE,掩蓋真實錯誤

根治策略:一步到位的構造函數

鐵律:構造函數必須初始化所有字段,建立完整有效對象。 若無法一次提供所有值,應提供多構造函數重載,而非暴露 setter。

無法重構舊代碼時的緩解措施

  1. 非空默認值:字段聲明處賦值(如 value = NonValue.ONLY),避免 NPE。
  2. 特殊默認類:用 Singleton 類(NonValue)代表「未初始化」,訪問時拋出帶上下文的異常(RuntimeException("Attempt to access uninitialized field")),優於 NPE。
  3. isInitialized() 方法:讓客戶代碼可快速檢查對象狀態。
  4. 額外構造函數:新代碼使用完整構造函數,舊代碼維持兼容。

反直覺的智慧:在基類定義拋異常的默認實現

如 List 接口在 Empty 子類中實現 getFirst() 拋異常,而非讓客戶 instanceof 判斷。雖違背「接口只定義有效操作」直覺,但消除了大量類型轉換與 instanceof,提升性能與可讀性。關鍵在於:設計動機決定模式適用性。

總結

Run-On Initialization 是構造函數職責不全的產物。新代碼堅持完整構造;舊代碼用默認類、非空值、狀態檢查法降低風險。下一期探討 Java 平台相關的「Gotcha」錯誤。

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