搜尋
首頁Javajava教程Java和Ceylon物件的建構與驗證的程式碼案例分享

當變換Java程式碼為Ceylon程式碼時,有時候我會遇到一些Java類別構造器混淆了驗證與初始化的情況。讓我們使用一個簡單但是人為的程式碼範例來說明我想闡述的意思。

一些壞程式碼

考慮下面的Java類別。 (夥計,不要在家裡寫這樣的程式碼)

public class Period {
    private final Date startDate;
    private final Date endDate;
    //returns null if the given String
    //does not represent a valid Date
    private Date parseDate(String date) {
       ...
    }
    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;
    }
    public Date getEndDate() {
        if (endDate==null)
            throw new IllegalStateException();
        return endDate;
    }
}

嘿,我之前已經警告過,它是人為的。但是,在實際Java程式碼中找個像這樣的東西其實並非不常見。

這裡的問題在於,即使輸入參數(在隱藏的parseDate()方法中)的驗證失敗了,我們還是會得到一個Period的實例。但是我們獲取的那個Period不是一個「有效的」狀態。嚴格地說,我的意思是什麼呢?

好吧,假如一個物件不能有意義地回應公用操作時,我會說它處於非有效狀態。在這個例子裡,getStartDate() 和getEndDate()會拋出一個IllegalStateException異常,這就是我認為不是「有意義」的一種情況。

從另一方面來看這個例子,在設計Period時,我們這兒出現了型別安全的失敗。未檢查的異常代表了類型系統中的一個「漏洞」。因此,一個更好的Period的類型安全的設計,會是一個不使用未檢查的異常—在這個例子中意味著不拋出IllegalStateException異常。

(實際上,在真實程式碼中,我更有可能遇到一個getStartDate() 方法它不檢查null ,在這個程式碼行之後就會導致一個NullPointerException異常,這就更加糟糕了。)

我們能夠輕鬆地轉換上面的Period類別成為Ceylon形式的類別:

shared class Period(String start, String end) {
    //returns null if the given String
    //does not represent a valid Date
    Date? parseDate(String date) => ... ;
    value maybeStartDate = parseDate(start);
    value maybeEndDate = parseDate(end);
    shared Boolean valid
        => maybeStartDate exists 
        && maybeEndDate exists;
    shared Date startDate {
        assert (exists maybeStartDate);
        return maybeStartDate;
    }
    shared Date endDate {
        assert (exists maybeEndDate);
        return maybeEndDate;
    }
}

當然了,這段程式碼也會遇到與原始Java程式碼相同的問題。兩個assert符號衝著我們大喊,在程式碼的類型安全上有一個問題。

讓Java程式碼變得更好

Java裡面我們要怎麼改進這段程式碼呢?好吧,這裡就是一個例子關於Java飽受詬病的已檢查異常會是一個非常合理的解決方法!我們可以稍微修改下Period來從它的構造器中拋出一個已檢查的異常:

public class Period {
    private final Date startDate;
    private final Date endDate;
    //throws if the given String
    //does not represent a valid Date
    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;
    }
    public Date getEndDate() {
        return endDate;
    }
}

#現在,使用這個解決方案,我們就不會獲取一個處於非有效狀態的Period,實例化Period的程式碼會由編譯器負責去處理無效輸入的情形,它會捕捉一個DateFormatException異常。

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

這是一個對已檢查異常不錯的、完美的、正確的使用,不幸的是我幾乎很少看到Java程式碼像上面這樣使用已檢查異常。

讓Ceylon程式碼變得更好

那麼Ceylon怎麼樣呢? Ceylon沒有已檢查異常,因而我們需要尋找不同的解決方法。典型地,在Java呼叫一個函數會拋出一個已檢查異常的情況中,Ceylon會呼叫函數傳回一個聯合類型。因為,一個類別的初始化不會傳回除了類別本身外的任何類型,我們需要提取一些混合的初始化/驗證的邏輯來使其成為一個工廠函數。

//returns DateFormatError if the given 
//String does not represent a valid Date
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(startDate, endDate) {
    shared Date startDate;
    shared Date endDate;
}

根據類型系統,呼叫者有義務去處理DateFormatError:

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

或者,如果我們不關心給定日期格式的實際問題(這是有可能的,假定我們工作的初始化程式碼遺失了那個資訊),我們可以使用Null而不是DateFormatError:

//returns null if the given String 
//does not represent a valid Date
Date? parseDate(String date) => ... ;
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(startDate, endDate) {
    shared Date startDate;
    shared Date endDate;
}

至少可以說,使用工廠函數的方法是優秀的,因為通常來說在驗證邏輯和物件初始化之間它具有更好的隔離。這一點在Ceylon中特別有用,在Ceylon中,編譯器在物件初始化邏輯中添加了一些非常嚴厲的限制,以確保物件的所有領域僅被賦值一次。

以上是Java和Ceylon物件的建構與驗證的程式碼案例分享的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
Java平台獨立性:OS之間的差異Java平台獨立性:OS之間的差異May 16, 2025 am 12:18 AM

Java在不同操作系統上的表現存在細微差異。 1)JVM實現不同,如HotSpot、OpenJDK,影響性能和垃圾回收。 2)文件系統結構和路徑分隔符不同,需使用Java標準庫處理。 3)網絡協議實現差異影響網絡性能。 4)GUI組件外觀和行為在不同系統上有別。通過使用標準庫和虛擬機測試,可減少這些差異的影響,確保Java程序穩定運行。

Java的最佳功能:從面向對象的編程到安全性Java的最佳功能:從面向對象的編程到安全性May 16, 2025 am 12:15 AM

javaoffersrobustobject-IentiendedProgrammming(OOP)和Top-Notchsecurityfeatures.1)OopinjavainCludesClasses,對象,繼承,多態性,和列出,andeclingfleximaintainablesys.ss.2)SecurityFeateTuersLudEtersludEterMachine(

JavaScript與Java的最佳功能JavaScript與Java的最佳功能May 16, 2025 am 12:13 AM

JavaScriptandJavahavedistinctstrengths:JavaScriptexcelsindynamictypingandasynchronousprogramming,whileJavaisrobustwithstrongOOPandtyping.1)JavaScript'sdynamicnatureallowsforrapiddevelopmentandprototyping,withasync/awaitfornon-blockingI/O.2)Java'sOOPf

Java平台獨立性:收益,限制和實施Java平台獨立性:收益,限制和實施May 16, 2025 am 12:12 AM

JAVAACHIEVESPLATFORMINDEPENTENCETHROUGHJAVAVIRTAILMACHINE(JVM)和BYTECODE.1)THEJVMINTERPRETSBBYTECODE,允許theingthesmecodetorunonanyanyanyanyplatformwithajvm.2)

Java:真實詞的平台獨立性Java:真實詞的平台獨立性May 16, 2025 am 12:07 AM

java'splatformendependecemeansapplicationscanrunonanyplatformwithajvm,使“ Writeonce,runanywhere”。

JVM性能與其他語言JVM性能與其他語言May 14, 2025 am 12:16 AM

JVM'SperformanceIsCompetitiveWithOtherRuntimes,operingabalanceOfspeed,安全性和生產性。 1)JVMUSESJITCOMPILATIONFORDYNAMICOPTIMIZAIZATIONS.2)c提供NativePernativePerformanceButlanceButlactsjvm'ssafetyFeatures.3)

Java平台獨立性:使用示例Java平台獨立性:使用示例May 14, 2025 am 12:14 AM

JavaachievesPlatFormIndependencEthroughTheJavavIrtualMachine(JVM),允許CodeTorunonAnyPlatFormWithAjvm.1)codeisscompiledIntobytecode,notmachine-specificodificcode.2)bytecodeisisteredbytheybytheybytheybythejvm,enablingcross-platerssectectectectectross-eenablingcrossectectectectectection.2)

JVM架構:深入研究Java虛擬機JVM架構:深入研究Java虛擬機May 14, 2025 am 12:12 AM

TheJVMisanabstractcomputingmachinecrucialforrunningJavaprogramsduetoitsplatform-independentarchitecture.Itincludes:1)ClassLoaderforloadingclasses,2)RuntimeDataAreafordatastorage,3)ExecutionEnginewithInterpreter,JITCompiler,andGarbageCollectorforbytec

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

WebStorm Mac版

WebStorm Mac版

好用的JavaScript開發工具

SublimeText3 Linux新版

SublimeText3 Linux新版

SublimeText3 Linux最新版

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

這個專案正在遷移到osdn.net/projects/mingw的過程中,你可以繼續在那裡關注我們。 MinGW:GNU編譯器集合(GCC)的本機Windows移植版本,可自由分發的導入函式庫和用於建置本機Windows應用程式的頭檔;包括對MSVC執行時間的擴展,以支援C99功能。 MinGW的所有軟體都可以在64位元Windows平台上運作。

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)