国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Java > 正文

Java和Ceylon對象的構(gòu)造和驗證

2019-11-26 13:33:53
字體:
供稿:網(wǎng)友

當(dāng)變換Java代碼為Ceylon代碼時,有時候我會遇到一些Java類構(gòu)造器混淆了驗證與初始化的情形。讓我們使用一個簡單但是人為的代碼例子來說明我想闡述的意思。

一些壞代碼

考慮下面的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; }}

嘿,我之前已經(jīng)警告過,它是人為的。但是,在實際Java代碼中找個像這樣的東西實際上并非不常見。

這里的問題在于,即使輸入?yún)?shù)(在隱藏的parseDate()方法中)的驗證失敗了,我們還是會獲得一個Period的實例。但是我們獲取的那個Period不是一個“有效的”狀態(tài)。嚴(yán)格地說,我的意思是什么呢?

好吧,假如一個對象不能有意義地響應(yīng)公用操作時,我會說它處于一個非有效狀態(tài)。在這個例子里,getStartDate() 和getEndDate()會拋出一個IllegalStateException異常,這就是我認(rèn)為不是“有意義的”一種情況。

從另外一方面來看這個例子,在設(shè)計Period時,我們這兒出現(xiàn)了類型安全的失敗。未檢查的異常代表了類型系統(tǒng)中的一個“漏洞”。因此,一個更好的Period的類型安全的設(shè)計,會是一個不使用未檢查的異常―在這個例子中意味著不拋出IllegalStateException異常。

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

我們能夠很容易地轉(zhuǎn)換上面的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; }}

當(dāng)然了,這段代碼也會遇到與原始Java代碼同樣的問題。兩個assert符號沖著我們大喊,在代碼的類型安全中有一個問題。

使Java代碼變得更好

Java里我們怎么改進(jìn)這段代碼呢?好吧,這兒就是一個例子關(guān)于Java飽受詬病的已檢查異常會是一個非常合理的解決方法!我們可以稍微修改下Period來從它的構(gòu)造器中拋出一個已檢查的異常:

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)在,使用這個解決方案,我們就不會獲取一個處于非有效狀態(tài)的Period,實例化Period的代碼會由編譯器負(fù)責(zé)去處理無效輸入的情形,它會捕獲一個DateFormatException異常。

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

這是一個對已檢查異常不錯的、完美的、正確的使用,不幸的是我?guī)缀鹾苌倏吹絁ava代碼像上面這樣使用已檢查異常。

使Ceylon代碼變得更好

那么Ceylon怎么樣呢?Ceylon沒有已檢查異常,因而我們需要尋找一個不同的解決方式。典型地,在Java調(diào)用一個函數(shù)會拋出一個已檢查異常的情形中,Ceylon會調(diào)用函數(shù)返回一個聯(lián)合類型。因為,一個類的初始化不返回除了類自己外的任何類型,我們需要提取一些混合的初始化/驗證的邏輯來使其成為一個工廠函數(shù)。

//returns DateFormatError if the given //String does not represent a valid DateDate|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ù)類型系統(tǒng),調(diào)用者有義務(wù)去處理DateFormatError:

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

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

//returns null if the given String //does not represent a valid DateDate? 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;}

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

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持武林網(wǎng)。

發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 兴文县| 伊川县| 高陵县| 措美县| 游戏| 如皋市| 黎平县| 曲靖市| 黎平县| 吉水县| 永德县| 鸡西市| 体育| 贵溪市| 友谊县| 彭水| 呼玛县| 宝坻区| 义马市| 孝义市| 临湘市| 渝北区| 焉耆| 竹溪县| 疏附县| 饶阳县| 汉沽区| 紫阳县| 荃湾区| 两当县| 宜川县| 青神县| 莱西市| 嘉定区| 米林县| 凉山| 仁布县| 博白县| 沧州市| 镇康县| 炎陵县|