此為過去的舊文,2014 年 4 月 26 日初次發表於 logdown。
今天來點輕鬆的,這應該算是看完《超越 Java -- 探討程式語言的未來》多年後最近再次思考的一些心得:近幾年 Java 太重視 Library (J2EE 已經變成龐然大物)了,忽略了語言本身的問題(J2SE 7 的 auto-closable resource in try-catch 和 J2SE 8 的 Lambda 恐怕是繼 J2SE 5 的 Generic/Autoboxing 後針對語言本身所做的少數改變)。
Java SE 8 已經發布,甚至短短一個月不到(2014/3/18 -> 2014/4/15),就發布的 Java SE 8 Update 5 (從Oracle接手後,版本號碼跳超快的),下一個版本 Java SE 9 似乎已經開始蠢蠢欲動,不過在接觸幾種不同語言後,其實有幾個語言特性 (不一定是功能),我到蠻希望 Java 能加入的。
第一個我希望加入的是 Property,其實蠻多語言都有類似的語言特性,例如 Objective C 和 C# 都有,property 可以像存取變數值那樣使用,例如 for(Publication* publication in person.publications)
取得著作,或是 page.Height = 400
指定頁面高度,但它和直接把成員變數宣告成 public 不同,因為 property 還是有存取權限的設定,由不同存取權限的 getter 和 setter 所組成的,所以在範例中,改變高度是會通知 handlers (observer pattern) 的。只是多數語言有提供預設實作,或是提供機制自動產生,例如 @synthesize firstName;
。雖然 Java 可以使用 Lombok 動生成 getter/setter,但終究不是語言的一部分,而且我討厭用 annotation 做這件事(好吧!關於 annotation 純屬我個人喜好問題)。
第二個特性是 Literal data structure declaration,JavaScript 和 Objective C 等語言都有提供類似的特性。有時候在處理資料時,只是想要個簡單的資料物件 (data object),但就是一定要寫個 class,然後提供 getter/setter 的實作,這實在太麻煩了,如下所示,馬上就能組出一個 company
資料物件,沒錯,Objective C 從 JavaScript Object Notation (JSON) 那裡參考來的,只是要加上小老鼠 @
作為識別。Java 也許該考慮一下!小抱怨一下,為什麼內建的 JSON API 只有在 J2EE 中才有,難道 client 不需要解析 JSON 嗎?真是奇怪的一件事。
第三個希望新增到Java中的特性是 Category,這是我在學 Objective C 後很喜歡的一個語言特性,category 是一種可以用來黏合新實作到既有物件的方式,但又不是繼承,因為型別沒有改變,也不是 C# 的 partial keyword。這在設計複雜的專案時很方便,可以依據功能分類到不同的檔案中,而且可以依據需求只使用部分的功能。例如:POJO (Plain Old Java Object) 物件與 JSON 之間的轉換,到底應該算是物件本身自己該做的事?還是由別的物件負責做轉換?
我剛開始學 OO 語言時,會覺得是前者,但後來多看了很多設計後,我傾向後者,畢竟物件可輸出成多種格式 (JSON或XML),想要新增一種輸出格式時,得修改原物件有點違反 open close principle,而且在沒有原始碼的情況下,修改原物件也不可能,只能用繼承,但繼承又會改變型態。但如果有 category 機制,就可以將新格式輸出的實作黏合到既有物件中。
例如,Person
物件在原本的 Person.h
中只需要提供 domain model 所需的邏輯即可,而 JSON 相關的邏輯實作則是放在 JSON 的 category 中,若需要 JSON 相關的邏輯實作,才需要匯入 (import) Person+JSON.h
,若不需要,只需匯入一般的 Person.h
即可,這時 JSON 相關的實作也看不到。而且在沒有原始碼的情況下也可以用 category 來黏合新實作,我就常用 category 替 NSString
加新東西。
第四個特性是 Extension,這也是 Objective C 的一個語言特性。我希望加入 Java 中是和測試有關,Objective C 雖然有 @public
、@protected
和 @private
關鍵字,但是用在成員變數上,而不是函式上。Objective C 沒有要求函式一定要宣告在 .h
檔中,所以大多數情況下是把不希望被知道的函式直接寫在 .m
檔中,有時候為了測試方便會希望,某些原本宣告成private的函式能在測試期間暫時變成 public。
這時 extension 就派上用場了,如下所示,將希望公開的函式放在 Person.h 檔中,不希望公開但希望在測試期間被看到的 private 函式則放 Person_Private.h
中,公開程式時只公開 Person.h
檔,Person_Private.h
檔則不公開,測試時匯入 Person_Private.h
檔就能看到想測的 private 函式 (其實,Objective C 的 extension 還可以更狠,連 extension 的 .h
檔都不需要,直接在測試程式中,強制把 private methods 變成公開的 XD)。雖然 Java 沒有 .h
標頭檔和 .m
實作檔分離的設計,但如果能有 private interface implementation 的話,也許可以提供類似的特性。
第五個特性是與 IDE 整合用的 Preprocessor。雖然有不少人因為 IDE 越來越笨重開始回歸單純,使用一般 (說一般也不對,因為還是有 syntax highlighted 等功能) 的文字編輯器寫程式,但我想還是有不少人是用 IDE 在寫程式 (我也一度覺得Eclipse超慢的,在想找替代品時發現 4.3 又變快了才繼續使用),Objective C 和 C# 在與 IDE 整合上就表現得很不錯,Java 有蠻多好的 IDE,但語言對於 IDE 則完全沒有支援。
像我就會依照功能整理程式碼,所以我會在 Objective C 裡用 #param mark - UITableViewDelegate Methods
將實作 UITableViewDelegate
的函式集中分區塊,或在 C# 裡用 #region Properties
和 #endregion
將所有的 properties 包起來成為一個區塊,當 IDE 看到這些 preprocessor 時,可以做最佳化顯示,例如在 XCode 裡,如果有使用 #param mark
,在上方導覽列的函示列表 (Figure 1) 就會根據 mark 的名稱將函式分區顯示,在找函式時更方便。
這幾年新出的語言都強打在少寫 code 和提高可讀性,更重要的是能更容易發展出 domain specific language,就這一點 Java 確實有點顯得疲態了。其實文中列的特性大多是一些語法糖衣,但對程式的可讀性和抽象度都能提昇不少,我覺得挺實用也很划算的。
過了 10 年 (突然發現正好整整十年),把文章從 logdown 搬過來時,發現 Java 雖然在語言本身真的有改變,像是導入 record,更強的 switch expression 等等,但 property 依然沒有;literal data structure declaration 也沒有,只能靠 record 稍微簡化一點;category (Swift 改稱為 extension) 也沒有,反倒是 Kotlin 加入了;extension (Swift 沒有對應的設計) 也是沒有,唯一有一點點關係的是 Java 9 導入了新的模組模型,但感覺很少人用;與 IDE 的整合也沒有。
只能說還是挺失望的,但 10 年過去,有些想法也改變了,像是 category 我現在就還好 (參閱 閒談軟體設計:Single Responsibility),若現在問我希望 Java 加什麼特性?就是語言直接支援 null
的處理,Optional
真的很難用 (參閱拙譯《沒有什麼比 Optional 更好,真的,沒有,更好》)...