當變換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)雲計算和容器化技術如Docker增強了Java的平台獨立性,但需要優化以適應不同雲環境。 2)WebAssembly通過GraalVM編譯Java代碼,擴展了其平台獨立性,但需與其他語言競爭性能。

不同JVM實現都能提供平台獨立性,但表現略有不同。 1.OracleHotSpot和OpenJDKJVM在平台獨立性上表現相似,但OpenJDK可能需額外配置。 2.IBMJ9JVM在特定操作系統上表現優化。 3.GraalVM支持多語言,需額外配置。 4.AzulZingJVM需特定平台調整。

平台獨立性通過在多種操作系統上運行同一套代碼,降低開發成本和縮短開發時間。具體表現為:1.減少開發時間,只需維護一套代碼;2.降低維護成本,統一測試流程;3.快速迭代和團隊協作,簡化部署過程。

Java'splatformindependencefacilitatescodereusebyallowingbytecodetorunonanyplatformwithaJVM.1)Developerscanwritecodeonceforconsistentbehavioracrossplatforms.2)Maintenanceisreducedascodedoesn'tneedrewriting.3)Librariesandframeworkscanbesharedacrossproj

要解決Java應用程序中的平台特定問題,可以採取以下步驟:1.使用Java的System類查看系統屬性以了解運行環境。 2.利用File類或java.nio.file包處理文件路徑。 3.根據操作系統條件加載本地庫。 4.使用VisualVM或JProfiler優化跨平台性能。 5.通過Docker容器化確保測試環境與生產環境一致。 6.利用GitHubActions在多個平台上進行自動化測試。這些方法有助於有效地解決Java應用程序中的平台特定問題。

類加載器通過統一的類文件格式、動態加載、雙親委派模型和平台無關的字節碼,確保Java程序在不同平台上的一致性和兼容性,實現平台獨立性。

Java編譯器生成的代碼是平台無關的,但最終執行的代碼是平台特定的。 1.Java源代碼編譯成平台無關的字節碼。 2.JVM將字節碼轉換為特定平台的機器碼,確保跨平台運行但性能可能不同。

多線程在現代編程中重要,因為它能提高程序的響應性和資源利用率,並處理複雜的並發任務。 JVM通過線程映射、調度機制和同步鎖機制,在不同操作系統上確保多線程的一致性和高效性。


熱AI工具

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

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

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

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

熱門文章

熱工具

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

EditPlus 中文破解版
體積小,語法高亮,不支援程式碼提示功能

SublimeText3 英文版
推薦:為Win版本,支援程式碼提示!

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