關於 Swift & Java 中 Optional 的設計

更新於 2024/04/27閱讀時間約 8 分鐘
此為過去的舊文,2014 年 7 月 6 日初次發表於 logdown。

近幾年電腦的運算效能已經好到一個程式語言的抽象程度遠比執行效率重要的層級,所以最近超多種程式語言冒出來(有種好累的感覺),特別是 Domain Specific Language,不過今天討論的還是 Genernal Purpose Language,只是在語法的抽象程度都過去的語言要好。

WWDC 2014 後就開始看《The Swift Programming Language》,看到 optionsals時,總覺得這好像看過耶,原來是在當初研究 Java 的 Stream API (參閱《Java 8 初探 - Stream》) 時,就看過 Java 8 內建相同的概念,但概念相同,實作卻不全然一樣,Java 的 Optional API level 的支援,Swift 則是從 language level 做支援。但如果真要說誰抄誰就很難說了 (ScalaOption 或是 Groovy 的 safe navigation operator 都是相似的的設計),畢竟最近的幾個新程式語言都從 functional programming language 借了很多特色,幾乎都支援 Lambda 就是一個明顯的例子。

不管是 Scala、Java 或是 Swift,概念上,Optioanl 是一個容器,裡面可能有值也可能沒有值,但是這個容器本身絕對不是 null (Java) 或 nil (Swift),因此在操作這個容器時,是絕對不會拋出NullPointerException (說是這麼說,但 Java 確實可以回傳空的 Optional,只能靠開發者堅守慣例才能讓這件事成真),但如果無視裡面是否有值就硬要取值還是會拋出 NoSuchElementException (Java) 或 Runtime error (Swift)。但是多了一層 Optional 是否真的能提高抽象程度呢?畢竟『是否有值』這件事還是得判斷,難道用了 Optional 就可以省去什麼麻煩嗎?首先看 Java 使用 Optional 後,使用上的差異吧!

以 Java 來說,後者搭配新的 Lambda expression 確實看起來賞心悅目許多。接著看 Swift 的例子,Swift的 if 和 Java一樣,只接受能產生 boolean 為結果的述句 (expression),所以 if possibleName 這個判斷式在解讀上和 C/C++ 不同 (C/C++ 的 if 是判斷述句的結果是否為非 0),但 Swift 是對 possibleName 這個 optional 物件先進行 evaluaton,若結果為 true,表示該物件是有值的,才執行大括弧裡的程式片段。除此之外,Swift 還有一種 optional binding 機制,即 if let name = possibleName,這一行的解讀為:先對 possibleName 物件進行evaluation,若結果為 true,則將 possibleName 所代表的物件指派給 name,因此在大括弧中 name物件保證是非 nil 可以安全存取的。


就上述的例子,是否有覺得抽象程度提高呢?或許再看二個例子吧,假設在使用某個沒有 API 文件的函式庫時,有 optioanl 和沒 optional 哪個版本能比較清楚知道解碼這個函式可能回傳一個不存在的物件呢?我想這應該很明顯,有 optional 的版本應該清楚很多,所以對我來說 optional 的引入,第一個好處是在做 API 設計時,可以提供一個很明確的回傳值定義,而不是透過文件的方式解釋回傳值可能不存在的情況。


剛才提到 Swift 對 optional 是 language level 的支援,除了 if 會自動對 optional 物件進行 evaluation和提供 optional binding 外,和 Groovy 一樣提供 optional chaining。假設 Person 物件有個可能不存在的 residence 屬性,代表其居住地,型別為 ResidenceResidenceAddress 紀錄地址,同樣可能不存在,Address 有個 street 屬性紀錄街名,同樣可能不存在,所以想透過 person 物件存取居住地的地址街名時,除了用 optional binding 層層解開外,Swift 提供 optional chaining:person.residence?.address?.street,只要在這串存取中任何一個屬性是不存在的,if 就會得到 false,也就不會執行指定的區塊,程式看起來較清爽簡潔許多。


那 Java 如何呢?Java 對 Optional 的支援大多是以 API 的形式存在,以剛剛的例子,若不想檢查 null,如下所示,需要搭配 Stream API 來使用,map(Function) 透過傳入的 Function 物件將 Optional<Person> 依序換轉 (想像成取得property) 成 Optional<Residence>Optional<Address>Optional<String>,最後用ifPresent(Consumer) 印出結果,就簡潔度來說 optional binding 確實簡潔多了。就抽象程度來說,用 Stream API 還真的需要一點想像力才能寫出這樣的程式碼,所以對我來說 optional chaining 的抽象度還是比較高一點。


整體來說,不論是 Swift 或是 Java,使用 Optional 來設計 API (注意,如果最後的例子中 getter 的回傳值是 Optional,那要用 flatMap(Function) 取代 map(Function),不然會拿到類似 Optional<Optional<Residence>> 的結果)應該都能提供更清楚的語義:該值可能不存在。

只是 Swift 以 language level 支援 Optional 確實比用 API level 支援的 Java 要簡潔和更具可讀性。不過,Java 是一個歷史悠久 (1995至今) 的語言,很難對 language 本身做出太大幅度的改變,反之,Swift 是一個全新的語言,從一開始的設計就將許多好的語言特性加入,確實讓人驚豔。


延伸閱讀


2024 補充

10 年過去,Java 已經敲敲升級到 Java 21,但在處理 null 上,仍然沒太多改善,但不難理解,對一個已經有廣大生態系的語言,以語言層級的方式支援 Optional,確實有點動搖國本的感覺,例如,真的類似 Swift 等語言,用 ? 代表一個 Optional 物件,假設既有的函數庫中,一個函式回傳一個物件,因為已經編譯成 JAR 檔了,原作者沒空處理,在新版本裡使用這個函式,編譯器應該視回傳值為 Optional 還是非 Optional?要保證安全,應該要視為 Optional,因為舊版的 Java 確實允許回傳空值,這時編譯器會報錯 (或是警告),光處理這些錯誤或警告,就是一件辛苦的差事。若視為非 Optional,等到執行時真的是 null,恐怕也不適合。但如果真要選,我會選前者,並將這類問題視為警告,讓開發者慢慢朝向新特性邁進,晚到遲到總比不到好。

avatar-img
53會員
104內容數
這是從 Medium 開始的一個專題,主要是想用輕鬆閒談的方式,分享這幾年軟體開發的心得,原本比較侷限於軟體架構,但這幾年的文章不僅限於架構,也聊不少流程相關的心得,所以趁換平台,順勢換成閒談軟體設計。
留言0
查看全部
avatar-img
發表第一個留言支持創作者!
Spirit的沙龍 的其他內容
這幾年新出的語言都強打在少寫 code 和提高可讀性,更重要的是能更容易發展出 domain specific language,就這一點 Java 確實有點顯得疲態了。其實文中列的特性大多是一些語法糖衣,但對程式的可讀性和抽象度都能提昇不少,我覺得挺實用也很划算的。
很明顯可以看到 parallelSort(T[], Comparator<T> 大概可以帶來 2.5 倍到接近 3 倍的效能增益 (和數量無關)。所以,結論是當需要處理大量資料的排序時,真的可以考慮使用 parallelSort(T[], Comparator<T>。
Java 8 有了 Base64 編解碼器,方便不少,不過 Apache Commons Codec 提供更多常用的編解碼器,其實是更方便的,但如果你的應用程式中只需要 Base64 編解碼器,在有 Java 8 的環境中確實不需要將 Apache Commons Codec 和專案一起打包。
default methods 似乎也引起不小的討論,因為 default methods 加上可以實作多個介面,已經有點像 C++ 的多重繼承了,只差在沒辦法繼承成員變數而已,是好是壞就看怎麼使用了。我個人覺得還蠻方便的
Lazy evaluation 的效益必須是在 pipe 的組合上有最佳化過的,若組合的不好反而更糟糕,且在 I/O 上幫助似乎也不大。parallel stream 要能發揮效果必須看資料的來源類型,不過要注意的是 parallel stream 也會使記憶體的使用量增加,使用上也要小心。
老實說,看到 Java Sream API 讓我感到相當親切,這應該跟我研究所多年的研究題目是 visual dataflow language 有關,Java Stream API 把迴圈給內化了,每個 operation 的重點是要做什麼,大大提高了程式的抽象化程度和可讀性。
這幾年新出的語言都強打在少寫 code 和提高可讀性,更重要的是能更容易發展出 domain specific language,就這一點 Java 確實有點顯得疲態了。其實文中列的特性大多是一些語法糖衣,但對程式的可讀性和抽象度都能提昇不少,我覺得挺實用也很划算的。
很明顯可以看到 parallelSort(T[], Comparator<T> 大概可以帶來 2.5 倍到接近 3 倍的效能增益 (和數量無關)。所以,結論是當需要處理大量資料的排序時,真的可以考慮使用 parallelSort(T[], Comparator<T>。
Java 8 有了 Base64 編解碼器,方便不少,不過 Apache Commons Codec 提供更多常用的編解碼器,其實是更方便的,但如果你的應用程式中只需要 Base64 編解碼器,在有 Java 8 的環境中確實不需要將 Apache Commons Codec 和專案一起打包。
default methods 似乎也引起不小的討論,因為 default methods 加上可以實作多個介面,已經有點像 C++ 的多重繼承了,只差在沒辦法繼承成員變數而已,是好是壞就看怎麼使用了。我個人覺得還蠻方便的
Lazy evaluation 的效益必須是在 pipe 的組合上有最佳化過的,若組合的不好反而更糟糕,且在 I/O 上幫助似乎也不大。parallel stream 要能發揮效果必須看資料的來源類型,不過要注意的是 parallel stream 也會使記憶體的使用量增加,使用上也要小心。
老實說,看到 Java Sream API 讓我感到相當親切,這應該跟我研究所多年的研究題目是 visual dataflow language 有關,Java Stream API 把迴圈給內化了,每個 operation 的重點是要做什麼,大大提高了程式的抽象化程度和可讀性。
你可能也想看
Google News 追蹤
Thumbnail
*合作聲明與警語: 本文係由國泰世華銀行邀稿。 證券服務係由國泰世華銀行辦理共同行銷證券經紀開戶業務,定期定額(股)服務由國泰綜合證券提供。   剛出社會的時候,很常在各種 Podcast 或 YouTube 甚至是在朋友間聊天,都會聽到各種市場動態、理財話題,像是:聯準會降息或是近期哪些科
Thumbnail
業餘的股票喜好者,自許績效能稍微贏過大盤即可(如果不行就考慮加入指數市場@_@),抵抗通膨對資產的侵蝕,目標並非想要賺一個股本(EPS 10元),而是想要享受投資過程中透過觀察及發覺來驗證自己想法的樂趣。
Thumbnail
#關於陪女溫習這回事 這是女兒升上中學後的第一次考試。 一如往常,我請了假陪她考試,但其實由小六開始,我已經沒有參與太多她溫習的事,請假只是為了接送她回家溫習。 我自己讀過中學所以知道由小學升讀中學是怎麼一回事,一直擔心她升上中學後會應付不來,儘管如此,我還是選擇放手讓她自己來,除非她有不懂的
Thumbnail
結合冥婚和同婚議題的《關於我和鬼變成家人的那件事》,巧妙的把臺灣習俗、 LGBT 元素融合成一部多元類型的電影,不僅榮登臺灣電影票房第七名,更獲選為代表臺灣參賽 2024 年第 96 屆奧斯卡金像獎「最佳國際影片獎」,並入圍第 60 屆金馬獎 8 項獎項,堪稱叫好又叫座。
Thumbnail
近幾年我開始對靈魂學感到興趣。 我沒有很認真的研究這門學問,只是看了很多本相關的書,簡單來說,靈魂學就是研究人類「生命本質」及「死後另類生命型態」,例如瀕死體驗、輪迴、出體、前世回溯等等。 我相信有靈魂的存在(怎麼可能沒有?),死後靈魂不會消失,死亡是從這邊到那邊,而誕生則是從那邊到這邊。人生只
Thumbnail
這是一個人人都要突顯自己希望能被看見的年代,也是一個總是需要在人前大張旗鼓說出自己那些可以端上檯面的才能,畫畫不是我的才能,我只是喜歡這件事,又「擅長」手工藝和開發商品,可以找我做設計排版做書,可以找我合作商品,但不要找我畫畫,因為這是一件,我最不擅長也無法幫別人完成需求的能力!
Thumbnail
我和鬼變成家人的那件事,是一件牽涉到同志與冥婚,光怪陸離的台灣電影。總是認為,電影刻意地把同志議題說得太着跡,也定了一重很深的意識形態,將同志影像及畫面化,反而會令觀眾去思考,究竟同志是否就是那樣。父子情設定很動人,也恰恰寫了父親那種口硬心軟的關切之情,可惜一切都來得太遲。人生本來就是要有遺憾...
Thumbnail
關於我曾經是個沒是整天捧著書看的文學人,也曾經是個想要推廣台灣文化資產的文資人,現在想起來根本恍如隔世啊!
隨著大數據、AI、資料科學的興起,越來越多人對用這些技術來交易感興趣,剛開始進入股市也是想運用機器學習在股市上,但越交易越覺得想分析股市是很困難的 因為無法取得足夠預測股價漲跌的特徵 模型提高準確度,一定是取得一些合理的特徵,這些特徵在丟模型前就可以預期會有好的效果或至少有個合理的說法 而什麼是股票
黑衣  月亮  麥香綠 菸 打勾勾 暗黑版面 清水加油站 勤美鏡子 中友 一中 玻璃屋 麻園頭溪的橋 八樓圍牆 桌上寫字(三個愛心) 你離開了 我還困在那裡。 
Thumbnail
*合作聲明與警語: 本文係由國泰世華銀行邀稿。 證券服務係由國泰世華銀行辦理共同行銷證券經紀開戶業務,定期定額(股)服務由國泰綜合證券提供。   剛出社會的時候,很常在各種 Podcast 或 YouTube 甚至是在朋友間聊天,都會聽到各種市場動態、理財話題,像是:聯準會降息或是近期哪些科
Thumbnail
業餘的股票喜好者,自許績效能稍微贏過大盤即可(如果不行就考慮加入指數市場@_@),抵抗通膨對資產的侵蝕,目標並非想要賺一個股本(EPS 10元),而是想要享受投資過程中透過觀察及發覺來驗證自己想法的樂趣。
Thumbnail
#關於陪女溫習這回事 這是女兒升上中學後的第一次考試。 一如往常,我請了假陪她考試,但其實由小六開始,我已經沒有參與太多她溫習的事,請假只是為了接送她回家溫習。 我自己讀過中學所以知道由小學升讀中學是怎麼一回事,一直擔心她升上中學後會應付不來,儘管如此,我還是選擇放手讓她自己來,除非她有不懂的
Thumbnail
結合冥婚和同婚議題的《關於我和鬼變成家人的那件事》,巧妙的把臺灣習俗、 LGBT 元素融合成一部多元類型的電影,不僅榮登臺灣電影票房第七名,更獲選為代表臺灣參賽 2024 年第 96 屆奧斯卡金像獎「最佳國際影片獎」,並入圍第 60 屆金馬獎 8 項獎項,堪稱叫好又叫座。
Thumbnail
近幾年我開始對靈魂學感到興趣。 我沒有很認真的研究這門學問,只是看了很多本相關的書,簡單來說,靈魂學就是研究人類「生命本質」及「死後另類生命型態」,例如瀕死體驗、輪迴、出體、前世回溯等等。 我相信有靈魂的存在(怎麼可能沒有?),死後靈魂不會消失,死亡是從這邊到那邊,而誕生則是從那邊到這邊。人生只
Thumbnail
這是一個人人都要突顯自己希望能被看見的年代,也是一個總是需要在人前大張旗鼓說出自己那些可以端上檯面的才能,畫畫不是我的才能,我只是喜歡這件事,又「擅長」手工藝和開發商品,可以找我做設計排版做書,可以找我合作商品,但不要找我畫畫,因為這是一件,我最不擅長也無法幫別人完成需求的能力!
Thumbnail
我和鬼變成家人的那件事,是一件牽涉到同志與冥婚,光怪陸離的台灣電影。總是認為,電影刻意地把同志議題說得太着跡,也定了一重很深的意識形態,將同志影像及畫面化,反而會令觀眾去思考,究竟同志是否就是那樣。父子情設定很動人,也恰恰寫了父親那種口硬心軟的關切之情,可惜一切都來得太遲。人生本來就是要有遺憾...
Thumbnail
關於我曾經是個沒是整天捧著書看的文學人,也曾經是個想要推廣台灣文化資產的文資人,現在想起來根本恍如隔世啊!
隨著大數據、AI、資料科學的興起,越來越多人對用這些技術來交易感興趣,剛開始進入股市也是想運用機器學習在股市上,但越交易越覺得想分析股市是很困難的 因為無法取得足夠預測股價漲跌的特徵 模型提高準確度,一定是取得一些合理的特徵,這些特徵在丟模型前就可以預期會有好的效果或至少有個合理的說法 而什麼是股票
黑衣  月亮  麥香綠 菸 打勾勾 暗黑版面 清水加油站 勤美鏡子 中友 一中 玻璃屋 麻園頭溪的橋 八樓圍牆 桌上寫字(三個愛心) 你離開了 我還困在那裡。