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

Java 7 新特性全景解析:語法糖、異常處理增強、Try-with-resources、腳本引擎 API 深度指南

     編輯:Java 程式設計入門

語法層面的甜蜜糖果

1. Switch 支援 String (JDK 7+)


String day = "MONDAY";
switch (day) {
    case "MONDAY": case "TUESDAY": case "WEDNESDAY":
    case "THURSDAY": case "FRIDAY":
        System.out.println("Workday"); break;
    case "SATURDAY": case "SUNDAY":
        System.out.println("Weekend"); break;
    default: throw new IllegalArgumentException("Invalid day: " + day);
}
// 實現原理:編譯器將 String switch 轉為 hashCode() + equals() 兩級判斷

2. 二進制字面量與數值分隔符


int mask = 0b1010_1100_1111_0000; // 0b/0B 前綴,_ 分隔提高可讀性
long creditCard = 1234_5678_9012_3456L; // 長整數同樣支援
// _ 不能出現在首尾、小數點旁、型別後綴前

異常處理兩大里程碑式改進

1. 多重捕獲


// JDK 7 前:需多個 catch 塊重複代碼
// JDK 7+:單一 catch 塊捕獲多種異常 (用 | 分隔)
try {
    // ... IO 操作
} catch (IOException | SQLException ex) {
    logger.error("資料存取失敗", ex);
    throw ex;
}
// 限制:捕獲的異常類型不能有父子繼承關係 (否則編譯錯誤)
// 異常參數隱含 final,不可在 catch 塊中重新賦值

2. 被壓制異常與 try-with-resources

痛點:finally 中關閉資源拋出異常會掩蓋 try 中的原始異常。


// JDK 7 前手動處理被壓制異常 (繁瑣)
FileInputStream in = null;
IOException primary = null;
try {
    in = new FileInputStream("data.txt");
    // 讀取...
} catch (IOException e) {
    primary = e;
} finally {
    if (in != null) {
        try { in.close(); }
        catch (IOException suppressed) {
            if (primary != null) primary.addSuppressed(suppressed);
            else primary = suppressed;
        }
    }
    if (primary != null) throw primary;
}

JDK 7 解決方案:Throwable.addSuppressed() + getSuppressed() 自動記錄;try-with-resources 自動關閉實現 AutoCloseable 的資源。


// 現代寫法:簡潔、安全、自動處理被壓制異常
try (FileInputStream in = new FileInputStream("data.txt");
     BufferedReader br = new BufferedReader(new InputStreamReader(in))) {
    String line = br.readLine();
    // 處理...
} catch (IOException e) {
    // e.getSuppressed() 可獲取關閉資源時產生的被壓制異常
    throw e;
}
// 編譯器自動生成 finally 區塊調用 close(),異常鏈完整保留

可變參數與泛型的類型安全增強

@SafeVarargs 註解 (JDK 7)


// 編譯器警告:泛型可變參數可能導致堆污染
@SafeVarargs // 開發者承諾:方法體內不會對泛型參數進行不安全操作 (如存入不同類型)
public static  void safeMethod(T... args) { ... }

// 限制:只能用於 final/static 方法或構造器
// 原則:只有確信類型安全時才加註解,否則掩蓋真實風險

腳本引擎 API (JSR 223):讓 Java 擁抱動態語言

Java 內建 javax.script 包,支援 JavaScript (Nashorn, JDK 8-14)、Groovy、JRuby、Jython、Lua 等腳本語言,實現規則引擎、動態配置、用戶腳本擴展、模板渲染等場景。

核心架構

  • ScriptEngineManager:引擎工廠,發現類路徑下的腳本引擎實現 (SPI 機制)。
  • ScriptEngine:執行腳本、綁定變量、編譯腳本、調用函數的核心介面。
  • Bindings (extends Map):名值對存儲,實現 Java ↔ 腳本雙向數據交換。
  • ScriptContext:執行上下文,包含多作用域 Bindings、輸入/輸出流、屬性。
  • Compilable:可選介面,支援腳本預編譯 (CompiledScript),重複執行效能大增。
  • Invocable:可選介面,支援直接調用腳本函數/方法、獲取腳本實現的 Java 介面代理。

快速上手:執行 JavaScript 片段


ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("JavaScript"); // 或 "nashorn", "graal.js"
if (engine == null) throw new IllegalStateException("找不到 JS 引擎");

engine.eval("print('Hello from JS');"); // 直接執行

Java ↔ 腳本雙向數據綁定 (Bindings)


// 1. Java 向腳本傳值
engine.put("user", new User("Alice", 25));
engine.put("items", Arrays.asList("Apple", "Banana"));

// 2. 腳本讀取 Java 變量、寫入結果
engine.eval("var total = items.length; print('User: ' + user.name + ', Items: ' + total);");

// 3. Java 獲取腳本產生的結果
Object total = engine.get("total"); // 類型自動轉換 (JS Number → Java Double/Long)
System.out.println("Total from script: " + total);

自定義 Bindings 作用域隔離


// 引擎預設 Bindings (ENGINE_SCOPE) 共享,可能造成線程安全問題
// 創建獨立 Bindings 實現請求級隔離
Bindings requestBindings = engine.createBindings();
requestBindings.put("requestId", UUID.randomUUID().toString());
engine.eval("print('Processing ' + requestId);", requestBindings); // 僅此次 eval 生效

ScriptContext 進階控制:輸入輸出重定向、多作用域屬性


ScriptContext ctx = engine.getContext();
// 重定向腳本輸出到檔案
ctx.setWriter(new FileWriter("script-output.log"));
engine.eval("print('這行會寫入檔案');");

// 多作用域屬性:ENGINE_SCOPE (引擎級) 優先於 GLOBAL_SCOPE (全域)
ctx.setAttribute("config", "engineValue", ScriptContext.ENGINE_SCOPE);
ctx.setAttribute("config", "globalValue", ScriptContext.GLOBAL_SCOPE);
Object val = ctx.getAttribute("config"); // 返回 "engineValue" (優先級高)

腳本預編譯 (Compilable) 提升重複執行效能


if (engine instanceof Compilable) {
    CompiledScript compiled = ((Compilable) engine).compile("function calc(x) { return x * x; }");
    for (int i = 0; i < 10000; i++) {
        compiled.eval(); // 無需重複解析,直接執行字節碼
    }
}

直接調用腳本函數/方法


engine.eval("function greet(name) { return 'Hello, ' + name; }");
if (engine instanceof Invocable) {
    Invocable inv = (Invocable) engine;
    Object result = inv.invokeFunction("greet", "World"); // 調用全局函數
    System.out.println(result); // Hello, World

    // 調用對象方法
    engine.eval("var obj = { sayHi: function(n) { return 'Hi, ' + n; } };");
    Object obj = engine.get("obj");
    Object result2 = inv.invokeMethod(obj, "sayHi", "Alice");
    System.out.println(result2); // Hi, Alice
}

腳本實現 Java 介面 (動態代理)


public interface Greeter { String greet(String name); }

// 腳本中實現介面
engine.eval("function greet(name) { return 'Welcome, ' + name; }");

if (engine instanceof Invocable) {
    Greeter greeter = ((Invocable) engine).getInterface(Greeter.class);
    System.out.println(greeter.greet("Bob")); // Welcome, Bob
    // Java 代碼完全感知不到實現來自腳本,解耦業務邏輯與實現技術
}

腳本引擎選型建議 (2024+)

引擎狀態特點推薦場景
Nashorn (jdk.scripting.nashorn)JDK 15 移除JS ES5/6 部分支援,無 WASM維舊專案 (JDK 8-14)
GraalVM JavaScript (GraalJS)活躍維護ES2023 完整支援、Node.js 相容、高效能、多語言互操作新專案首選 (需引入 graal-sdk 依賴)
Rhino維護模式舊版 JS,純 Java 實現極簡環境、Android (舊版)
Groovy活躍Java 語法超集、DSL 強、編譯靜態/動態規則引擎、構建腳本、測試

總結

Java 7 以 語法糖 (String switch, 二進制字面量, 數值分隔符)、異常處理現代化 (多重捕獲, try-with-resources, 被壓制異常)、類型安全增強 (@SafeVarargs) 大幅提升開發體驗;腳本引擎 API (JSR 223) 則為 Java 應用注入動態性,支援業務規則外部化、用戶腳本擴展、多語言協作。現代專案建議:語法特性全面採用、異常處理統一遷移至 try-with-resources、腳本引擎選 GraalJS 或 Groovy,並嚴格控制腳本執行權限 (沙箱、超時、資源限制) 確保安全。

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