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

Java 與 Ceylon 物件建構驗證對比:從防禦性編程到類型安全工廠模式

     編輯:Java 相關知識

問題代碼:Java 防禦性建構子

public class Period {
    private final Date startDate;
    private final Date endDate;
    
    private Date parseDate(String date) { ... } // 可能回傳 null
    
    public Period(String start, String end) {
        startDate = parseDate(start); // 無驗證直接賦值
        endDate = parseDate(end);
    }
    
    public boolean isValid() { 
        return startDate != null && endDate != null; 
    }
    
    public Date getStartDate() {
        if (startDate == null) throw new IllegalStateException();
        return startDate;
    }
    // ...
}

缺陷:物件可能處於「無效狀態」 (欄位為 null),呼叫 getter 拋出未檢查異常,違反類型安全,調用者易誤用。

改良一:Java 檢查式異常 (Checked Exception)

public class Period {
    private final Date startDate;
    private final Date endDate;
    
    private Date parseDate(String date) throws DateFormatException { ... }
    
    public Period(String start, String end) throws DateFormatException {
        startDate = parseDate(start);
        endDate = parseDate(end);
    }
    
    public Date getStartDate() { return startDate; } // 保證非 null
    public Date getEndDate() { return endDate; }
}

調用者被迫處理異常:

try {
    Period p = new Period(start, end);
} catch (DateFormatException e) { ... }

優點:編譯器保證物件有效性。缺點:Java 檢查式異常常被濫用/吞噬,導致樣板碼膨脹。

Ceylon 方案:工廠函數 + 聯合類型

Ceylon 無檢查式異常,採用聯合類型 表達「成功或失敗」:

方案 A:錯誤類型聯合

// 解析函數回傳 Date | DateFormatError
Date|DateFormatError parseDate(String date) => ...;

shared Period|DateFormatError parsePeriod(String start, String end) {
    value startDate = parseDate(start);
    if (is DateFormatError startDate) return startDate;
    value endDate = parseDate(end);
    if (is DateFormatError endDate) return endDate;
    return Period(startDate, endDate);
}

shared class Period(Date startDate, Date endDate) {
    shared Date startDate;
    shared Date endDate;
}

調用處:

value p = parsePeriod(start, end);
if (is DateFormatError p) { ... } else { ... }

方案 B:Optional 型別 (Null 聯合)

Date? parseDate(String date) => ...; // 可能為 null

shared Period? parsePeriod(String start, String end) =>
    if (exists startDate = parseDate(start), exists endDate = parseDate(end))
        then Period(startDate, endDate)
        else null;

shared class Period(Date startDate, Date endDate) {
    shared Date startDate;
    shared Date endDate;
}

核心差異總結

維度Java (檢查式異常)Ceylon (聯合類型/工廠)
表達失敗拋出異常回傳聯合類型 (T|Error 或 T?)
強制處理編譯器強制 try-catch編譯器強制類型窄化
建構子職責驗證+初始化混合純初始化,驗證移至工廠
物件不變性final 欄位保證value/共享屬性保證
程式碼結構分散在建構子/調用處集中在工廠函數

設計原則啟示

  1. 建構子只做初始化:複雜驗證、資源獲取、副作用移至工廠方法
  2. 失敗即類型一部分:用聯合類型/Optional/Result 型別替代異常控制流
  3. 不可變物件:建構後狀態固定,消除「無效狀態」可能性
  4. 編譯器輔助:利用類型系統在編譯期發現錯誤,而非執行期

總結

Java 與 Ceylon 在物件建構驗證上的差異,折射出兩種語言哲學:Java 依賴異常機制與防禦性檢查,Ceylon 則將失敗納入類型系統,配合工廠函數實現更清晰的職責分離。現代 Java 開發可引入 Optional、Result (Vavr) 或自訂密封類別模擬聯合類型,逐步邁向類型安全的建構模式。

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