協做翻譯java
原文:A Kotlin Wishlist for Java算法
連接:https://dzone.com/articles/a-kotlin-wishlist-for-java編程
譯者:imqipan, Tocy, dreamanzhao, 句號句號, Tot_ziens設計模式
毫無疑問,當談到編程語言時,Java 已佔領上風,並被認爲是最重要的開發語言之一。然而,在基於 JVM 的基礎上還開發了一些語言,好比說 Kotlin 。markdown
Kotlin 對於現代化的多平臺應用是一種靜態類的編程語言。儘管我已經從事 Java 開發有至關長的時間,可是在作一個數據-匿名化的項目時使我感受到 Java 須要從 Kotlin 引入一些東西。編程語言
下面是一些我願意看到的在 Java 中佔有一席之地的 Kotlin 特性。ide
提倡不可變函數
Java 9 引入了工廠方法建立集合,以此提倡不可變。但能在語言級別集成不可變,而非經過包裝生成不可變集合將是很是不錯的方式。existingDepartments() 是一個 Kotlin 的返回一個不可變字符串列表的函數。優化
Java 9 在嘗試添加、刪除一個不可變列表中的元素時將會拋出一個 UnsupportedOperationException 異常。但如可變與不可變的接口徹底隔離,避免給任何不可變集合暴露任何添加、刪除的接口將是不錯的。ui
//pre Java 8 public List<String> existingDepartments() { return new ArrayList<String>(){{ add("Human Resources"); add("Learning & Development"); add("Research"); }}; }//Java 8public List<String> existingDepartments() { return Stream.of("Human Resources", "Learning & Development", "Research") .collect(Collectors.toList()); }//Java 9public List<String> existingDepartments() { return List.of("Human Resources", "Learning & Development", "Research"); }
清晰對待不可變集合,堅定反對暴露接口而後拋出 UnsupportedOperationExceptions 異常。
方法參數默認爲 final
爲提高不可變性及避免因爲變化致使的錯誤,至少能夠考慮使缺省的方法參數爲 final 。
add() 函數的參數是 val ,其默認是不能改變的,這意味着做爲任何函數的客戶端,我均可以放心:函數不會改變傳遞給它的參數(不要與 object mutation 混淆)。
使方法參數默認爲 final 可能而且很大可能會破壞 Java 升級後的現存代碼基礎,但值得一提。
在編譯時處理NULL
全部的java開發者必定知道臭名昭著的NullPointerException。Kotlin邁出了重要的一步在編譯時處理NULLs。在顯式聲明以前,一切都是非空的。
Java 8不是出於一樣的緣由引入了Optional嗎?讓咱們看一個例子:
這個Employee 類具備非空id和可選(可空)部門的主構造函數。爲id傳遞null將致使編譯時錯誤。
departmentName()函數使用可選操做符訪問Department的name屬性?在可空的字段上,若是department爲null,name將會不被訪問而且左手邊的表達式[department?.name]將會返回null。三元操做符?:若是在表達式的左邊爲null將會返回右手邊的 ("Unassigned")。
//Java 8class Employee { private Integer id; private Optional<Department> department Employee(Integer id, Optional<Department> department){ this.id = id; this.department = department; } public String departmentName() { return department.orElse("Unassigned"); } }/** Employee needs a non-nullable "id" and an optional department to be constructed. Employee employee = new Employee(null, null); <b>NPE !!!</b> **/
Optional不會保護NPE的代碼,可是也有它的優勢:
它使域模型變得清晰。Employee類有可選的department,這就足以得出結論,每一個員工均可能沒有被分配到一個部門。
它在departmentName()方法中促進可組合性。
在編譯時處理NULLs應該能夠經過刪除if語句、對象的形式中的沒必要要的NULL檢查來實現更乾淨的代碼。Objects.requireNonNull, Preconditions.checkNotNull等其餘任何形式(的沒必要要的NULL檢查)。
改進Lambda表達式
Java 8引入的lambda表達式是創建在函數式接口和函數描述符的基礎上的,這就意味着每個lambda表達式都會映射到一個定義在函數式接口中的抽象方法。這是一種高效的方法,他受權給一個只有一個抽象方法(即函數描述符)的接口(即函數式接口)能夠建立一個lambda表達式。
上述代碼中,變量isPositive就是一個函數,它接受一個整形變量爲參數而且返回一個布爾類型值。這個變量的值就是一個函數的定義或者是定義在花括號中的一個lambda表達式,這個函數能夠檢查傳進來的參數是否大於零。
然而,在下面的代碼中,Predicate是包含一個抽象函數test()的函數式接口——他能夠接受一個類型爲T的參數並返回一個布爾類型值。
所以,isPositive能夠接受一個整型變量做爲參數並檢查這個參數是否大於零。因此咱們須要在使用isPositive時調用test()方法。
lambda表達式不該該依賴於函數式接口和其中的函數描述符。
支持擴展函數
Kotlin 支持擴展函數,以在無需繼承或裝飾其餘類的狀況下給函數提供新功能。
如下是一個擴展函數的案例,返回 String 最後的一個字符。
lastChar() 是定義在 String 類上的一個拓展函數,這裏 String 也被稱爲接收對象。經過 "Kotlin".lastChar() 來觸發函數。
拓展函數在沒有繼承和任何設計模式的狀況下,能夠拓展函數新特性。
尾部遞歸
Kotlin 支持 Tail-recursion(尾部遞歸)。尾部遞歸是遞歸的一種形式,其遞歸調用的是函數尾部最後的一條指令。這樣一來,咱們無須擔憂以前的值,一個棧楨知足全部的遞歸調用;尾部遞歸是優化遞歸算法的一種方式。
另外,尾部遞歸能夠很容易的轉換爲迭代的方式。
當函數用 tailrec 修飾符標識並知足所需的方式時,編譯器會對遞歸進行優化,並以快速高效的遞歸版本替換。
實際而言,尾部遞歸以固定的棧楨空間執行,它只是迭代過程的另外一種表達式。
Java 並不在編譯器級別直接支持尾部調用優化,不過能夠經過 lambda 表達式實現,可是期待能在編譯層面看到尾部遞歸算法。
其餘
總之,做爲開發人員,咱們總會犯錯誤(漏掉 NULL 檢查、改動集合數據等),但在語言級別上提供這些功能將使編程更輕鬆並儘量避免出現錯誤。