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

《編寫高質量代碼》讀書筆記:建議 16-20 深度解析

     編輯:Java 綜合教學

前言

本文繼續解讀《編寫高質量代碼:改善 Java 程序的 151 個建議》第一章中第 16 至 20 條建議,涵蓋腳本語言應用、動態編譯、instanceof 陷阱、斷言最佳實踐以及常量替換風險等核心主題。

建議 16:易變業務使用腳本語言編寫

為何 Java 需要腳本語言?

腳本語言(如 Groovy、JavaScript、Ruby)具備三大特性:運行期解釋執行、動態類型、語法靈活。這彌補了 Java 強編譯、靜態類型、部署流程繁瑣的短板,實現「業務邏輯熱更新、無需重啟 JVM」。

JSR-223 與 Java 腳本引擎

Java 6 引入 JSR-223 規範,提供統一的 javax.script API。只要腳本語言實現該規範,即可在 JVM 上運行。Java 默認內置 Nashorn(Java 8)或 Rhino(Java 6/7)JavaScript 引擎。

實戰範例:業務公式熱加載

// model.js
function formula(var1, var2) { return var1 + var2 * factor; }

Java 端通過 ScriptEngine 加載腳本,利用 Bindings 注入上下文變量 factor,並以 Invocable 調用腳本函數。修改 model.js 將乘法改為減法後,無需重啟 JVM 即可生效,完美模擬線上業務變更場景。

jrunscript 命令行工具

JDK 自帶 jrunscript 可直接運行腳本文件,跨平台、無需啟動完整 JVM,適合構建腳本、部署腳本等自動化場景。

建議 17:慎用動態編譯

Java Compiler API (JSR-199)

Java 6 提供 javax.tools.JavaCompiler,支持運行時編譯字符串、文件、數據庫中的源碼。核心步驟:獲取編譯器 → 構建 JavaFileObject → 設置編譯選項(如 -d 輸出目錄) → 執行編譯任務 → 反射加載類並調用方法。

適用場景與替代方案

  • 動態代理生成、規則引擎、模板引擎、插件熱插拔。
  • 但靜態編譯已能解決 99% 問題,且腳本語言(Groovy、JRuby)提供更優雅的動態能力,動態編譯引入的複雜度(類加載隔離、安全性、調試困難)往往得不償失。

建議 18:避免 instanceof 非預期結果

核心規則速查

表達式結果說明
"String" instanceof Objecttrue字符串字面量是 Object 實例
new String() instanceof Stringtrue基本語義
new Object() instanceof Stringfalse父類實例不是子類實例
'A' instanceof Character編譯錯誤基本類型不能直接用 instanceof
null instanceof Stringfalsenull 不是任何類的實例
(String) null instanceof Stringfalse強轉後仍為 null
new Date() instanceof String編譯錯誤無繼承關系的類型不可判斷
泛型擦除後 T instanceof Datefalse運行期 T 擦除為 Object

最佳實踐

  • 優先使用多態設計,減少 instanceof 使用。
  • 若必須使用,確保類型層級關系清晰,避免橫向轉型判斷。
  • 泛型場景下謹記類型擦除導致運行期類型信息丟失。

建議 19:斷言絕對不是雞肋

斷言語法與特性

assert booleanExpression;
assert booleanExpression : "error message";
  • 默認關閉,需啟動參數 -ea 或 -enableassertions 開啟。
  • 失敗拋出 AssertionError(繼承自 Error),屬不可恢復的嚴重錯誤。

兩大禁區

  1. 公開方法參數校驗:斷言可被關閉,導致生產環境失效,違背契約。應用 if (arg == null) throw new IllegalArgumentException()。
  2. 斷言表達式包含副作用邏輯:如 assert list.remove(item),關閉斷言後邏輯不執行,引發嚴重 Bug。

三大推薦使用場景

  1. 不可達代碼斷言:default: assert false : "不可能到達";
  2. 私有方法前置/後置條件檢查:驗證內部不變量。
  3. 程序探針:關鍵變量關係驗證,如 assert var1 == var2 * 2。

建議 20:不要只替換一個類文件

常量內聯陷阱

final 修飾的基本類型與字符串屬於「穩定態」,編譯器會在編譯期將其值內聯到調用方的字節碼中(而非符號引用)。

血淚案例還原

  1. 定義 Constant.MAX_AGE = 150,編譯 Client 類,字節碼寫死 150。
  2. 修改常量為 180,僅重新編譯 Constant 類,替換 Constant.class 到生產環境。
  3. 運行 Client 仍輸出 150!因為 Client.class 字節碼裡寫死的是舊值。

引用類型不受影響

若常量為對象引用(非基本類型/String),屬「軟 final」,編譯器保留符號引用,替換類文件後可獲取新值。

鐵律:整體 WAR/JAR 包發布

嚴禁單個 .class 文件熱替換發布! IDE 自動編譯掩蓋了此風險,生產環境必須全量構建發布,確保所有依賴類同步更新。

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