Java和Ceylon對(duì)象的構(gòu)造和驗(yàn)證
當(dāng)變換Java代碼為Ceylon代碼時(shí),有時(shí)候我會(huì)遇到一些Java類(lèi)構(gòu)造器混淆了驗(yàn)證與初始化的情形。讓我們使用一個(gè)簡(jiǎn)單但是人為的代碼例子來(lái)說(shuō)明我想闡述的意思。
一些壞代碼
考慮下面的Java類(lèi)。(伙計(jì),不要在家里寫(xiě)這樣的代碼)
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; } }
嘿,我之前已經(jīng)警告過(guò),它是人為的。但是,在實(shí)際Java代碼中找個(gè)像這樣的東西實(shí)際上并非不常見(jiàn)。
這里的問(wèn)題在于,即使輸入?yún)?shù)(在隱藏的parseDate()方法中)的驗(yàn)證失敗了,我們還是會(huì)獲得一個(gè)Period的實(shí)例。但是我們獲取的那個(gè)Period不是一個(gè)“有效的”狀態(tài)。嚴(yán)格地說(shuō),我的意思是什么呢?
好吧,假如一個(gè)對(duì)象不能有意義地響應(yīng)公用操作時(shí),我會(huì)說(shuō)它處于一個(gè)非有效狀態(tài)。在這個(gè)例子里,getStartDate() 和getEndDate()會(huì)拋出一個(gè)IllegalStateException異常,這就是我認(rèn)為不是“有意義的”一種情況。
從另外一方面來(lái)看這個(gè)例子,在設(shè)計(jì)Period時(shí),我們這兒出現(xiàn)了類(lèi)型安全的失敗。未檢查的異常代表了類(lèi)型系統(tǒng)中的一個(gè)“漏洞”。因此,一個(gè)更好的Period的類(lèi)型安全的設(shè)計(jì),會(huì)是一個(gè)不使用未檢查的異?!谶@個(gè)例子中意味著不拋出IllegalStateException異常。
(實(shí)際上,在真實(shí)代碼中,我更有可能遇到一個(gè)getStartDate() 方法它不檢查null ,在這個(gè)代碼行之后就會(huì)導(dǎo)致一個(gè)NullPointerException異常,這就更加糟糕了。)
我們能夠很容易地轉(zhuǎn)換上面的Period類(lèi)成為Ceylon形式的類(lèi):
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; } }
當(dāng)然了,這段代碼也會(huì)遇到與原始Java代碼同樣的問(wèn)題。兩個(gè)assert符號(hào)沖著我們大喊,在代碼的類(lèi)型安全中有一個(gè)問(wèn)題。
使Java代碼變得更好
Java里我們?cè)趺锤倪M(jìn)這段代碼呢?好吧,這兒就是一個(gè)例子關(guān)于Java飽受詬病的已檢查異常會(huì)是一個(gè)非常合理的解決方法!我們可以稍微修改下Period來(lái)從它的構(gòu)造器中拋出一個(gè)已檢查的異常:
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; } }
現(xiàn)在,使用這個(gè)解決方案,我們就不會(huì)獲取一個(gè)處于非有效狀態(tài)的Period,實(shí)例化Period的代碼會(huì)由編譯器負(fù)責(zé)去處理無(wú)效輸入的情形,它會(huì)捕獲一個(gè)DateFormatException異常。
try { Period p = new Period(start, end); ... } catch (DateFormatException dfe) { ... }
這是一個(gè)對(duì)已檢查異常不錯(cuò)的、完美的、正確的使用,不幸的是我?guī)缀鹾苌倏吹絁ava代碼像上面這樣使用已檢查異常。
使Ceylon代碼變得更好
那么Ceylon怎么樣呢?Ceylon沒(méi)有已檢查異常,因而我們需要尋找一個(gè)不同的解決方式。典型地,在Java調(diào)用一個(gè)函數(shù)會(huì)拋出一個(gè)已檢查異常的情形中,Ceylon會(huì)調(diào)用函數(shù)返回一個(gè)聯(lián)合類(lèi)型。因?yàn)?,一個(gè)類(lèi)的初始化不返回除了類(lèi)自己外的任何類(lèi)型,我們需要提取一些混合的初始化/驗(yàn)證的邏輯來(lái)使其成為一個(gè)工廠函數(shù)。
//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; }
根據(jù)類(lèi)型系統(tǒng),調(diào)用者有義務(wù)去處理DateFormatError:
value p = parsePeriod(start, end); if (is DateFormatError p) { ... } else { ... }
或者,如果我們不關(guān)心給定日期格式的實(shí)際問(wèn)題(這是有可能的,假定我們工作的初始化代碼丟失了那個(gè)信息),我們可以使用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; }
至少可以說(shuō),使用工廠函數(shù)的方法是優(yōu)秀的,因?yàn)橥ǔ?lái)說(shuō)在驗(yàn)證邏輯和對(duì)象初始化之間它具有更好的隔離。這點(diǎn)在Ceylon中特別有用,在Ceylon中,編譯器在對(duì)象初始化邏輯中添加了一些非常嚴(yán)厲的限制,以保證對(duì)象的所有領(lǐng)域僅被賦值一次。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- java構(gòu)造函數(shù)示例(構(gòu)造方法)
- Java中子類(lèi)調(diào)用父類(lèi)構(gòu)造方法的問(wèn)題分析
- Java中構(gòu)造、生成XML簡(jiǎn)明教程
- java繼承中的構(gòu)造方法實(shí)例解析
- 簡(jiǎn)單談?wù)刯ava中匿名內(nèi)部類(lèi)構(gòu)造函數(shù)
- Java基礎(chǔ)教程之構(gòu)造器與方法重載
- java用靜態(tài)工廠代替構(gòu)造函數(shù)使用方法和優(yōu)缺點(diǎn)
- 使用Java構(gòu)造和解析Json數(shù)據(jù)的兩種方法(詳解一)
- 講解Java中如何構(gòu)造內(nèi)部類(lèi)對(duì)象以及訪問(wèn)對(duì)象
- java中的靜態(tài)代碼塊、構(gòu)造代碼塊、構(gòu)造方法詳解
相關(guān)文章
SpringBoot系列教程之dubbo和Zookeeper集成方法
這篇文章主要介紹了SpringBoot系列教程之dubbo和Zookeeper集成方法,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-09-09JFinal實(shí)現(xiàn)偽靜態(tài)的方法
JFinal 是基于 Java 語(yǔ)言的極速 WEB + ORM 框架,其核心設(shè)計(jì)目標(biāo)是開(kāi)發(fā)迅速、代碼量少、學(xué)習(xí)簡(jiǎn)單、功能強(qiáng)大、輕量級(jí)、易擴(kuò)展、Restful。這篇文章主要介紹了JFinal實(shí)現(xiàn)偽靜態(tài),需要的朋友可以參考下2018-04-04Java中的synchronized?優(yōu)化方法之鎖膨脹機(jī)制
這篇文章主要介紹了Java中的synchronized?優(yōu)化方法之鎖膨脹機(jī)制,鎖膨脹機(jī)制是提升?synchronized?性能最有利的方法之一,下面我們就來(lái)看看什么事鎖膨脹及鎖膨脹的各種細(xì)節(jié)2022-05-05Java中List、Set、Map的區(qū)別和實(shí)現(xiàn)方式示例代碼
這篇文章主要介紹了Java中List、Set、Map的區(qū)別和實(shí)現(xiàn)方式示例代碼,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-06-06深入淺析Java中普通代碼塊、構(gòu)造代碼塊與靜態(tài)代碼塊
這篇文章主要介紹了Java中普通代碼塊、構(gòu)造代碼塊與靜態(tài)代碼塊的相關(guān)資料,靜態(tài)代碼塊>Main()>構(gòu)造代碼塊 。非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-08-08java書(shū)店系統(tǒng)畢業(yè)設(shè)計(jì) 用戶(hù)模塊(3)
這篇文章主要介紹了java書(shū)店系統(tǒng)畢業(yè)設(shè)計(jì),第三步系統(tǒng)總體設(shè)計(jì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-10-10