當變換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中文網其他相關文章!

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

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

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

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

java'splatformendependecemeansapplicationscanrunonanyplatformwithajvm,使“ Writeonce,runanywhere”。

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

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

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


熱AI工具

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

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

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

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

熱門文章

熱工具

WebStorm Mac版
好用的JavaScript開發工具

SublimeText3 Linux新版
SublimeText3 Linux最新版

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

SublimeText3漢化版
中文版,非常好用

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