Java的演化-Java8實戰筆記
一個語言要想一直有活力,它也需要跟隨著時代的變化去進步,Java作為一個古老的語言,它其實有太多的歷史包袱,在改變的過程中需要考慮很多,但是它也在慢慢的演變,鞏固自己的城墻,不讓自己被遺忘在歷史中(不少的編程語言已經隨著時間的推移,消失在人們的視線中)。當然,作為一個拿Java語言當成主語言的程序員,它的進步其實也在延長我們的職業生涯。
Java8帶來了很多新的特性,雖然Java8發布已經很久了,但是一直沒有系統的學習,所以這部分一直沒有進行總結。前東家考慮到與之前系統的兼容,技術標準將JDK7作為開發工具,這樣也無法利用Java8帶來的新特性。其實Java作為一個廣泛應用的語言來說,它自己的發布周期已經考慮了向前兼容,所以即使升級了JDK版本,其實也不會帶來太大的困擾,追隨最新的技術,讓員工能夠學習到新的技術標準,其實也是讓員工更加穩定的一種策略,同時在解決問題的同時,既得到了鍛煉,同時也獲得了成就感。這點也很重要。
函數
- Java8 Lambda的引入可以說是一種非常重要的特性,可以說Java中新增了一種值的屬性,這種值的類型是函數(這種特性在其他語言當中很早的就支持了,Java其實已經有些慢動作了)。
所以當你想要
- 排序一個Collection
- 聲明一個Thread
- ...
已經不需要去實現一個匿名類了,匿名類太多的無用代碼,直接傳遞Lambda函數更加簡潔,易讀。
Lambda聲明方式(arg1, arg2,...) -> {statement}
,其中單句的return expression;
可以簡寫為(arg1, arg2,...) -> expression
。
- Java還引入了一種引用已有方法的語法糖,這個特性稱為方法引用,可以進一步的簡化代碼。
- 靜態方法引用
- 指向任意類型實例方法引用
- 指向現有對象實例的方法引用
- 現在已經有傳入的參數了,但是如果聲明一個函數的參數為lambda類型該如何聲明,此時就需要使用函數接口了,lambda的類型在Java中是以函數接口實現的,函數接口是有且僅有一個抽象方法的接口,Java中已經提供了部分可以直接使用的函數接口,當不滿足需求時我們在聲明自己的函數接口即可。
Stream
Stream的強大在於它可以讓你以聲明性的方式處理數據集,同時,如果數據處理過程中數據處理過程,處理器以及收集器(這些後面會介紹)沒有副作用(函數式編程思想裏的一個概念),Stream可以很簡單,方便的利用多核架構的優勢,自動的並行執行。所以它的兩個強大優點:聲明式數據處理,自動的並行執行。讓我們看看這兩個Stream的優勢,當你熟練使用,一定會對它愛不釋手的。
如果你了解RxJava背後的思想,其實這個和RxJava使用非常相似,當然RxJava功能比Stream要強大一些,但是思考的時候也是利用這種圖形來思考數據處理,RxJava是簡化異步編程的一種模型,如果不了解可以去學習一下,很方便的一個工具。這裏多扯一句,現在高並發的環境下,對異步的需求越來越多,這樣在IO密集的場景下節省資源,可以支持高並發,但是異步編程一個缺點就是不符合人們的思考習慣,所以寫起來很復雜。RxJava的思想一定程序上減少了這種不方便。
但是新進的語言Go就從另外一種角度解決了這個問題,它在runtime支持協程的概念,你可以理解協程就是可以共享一個線程的幾個程序塊,由程序員去管理協程之間的切換。這個好處是充分利用了線程,並且可以容忍用戶以同步的模型去編寫代碼,解決了異步編程中不符合人們思考的習慣。當然這只是我粗鄙的理解,Go語言是值得學習的語言,可以拿來作為一個備選語言學習。
Steam上的操作可以分為兩大類操作
中間操作
終端操作
Stream上有一個非常好用的終端操作,它就是收集器。Java中提供了一些預定義的收集器,這些收集器均通過Collector
類提供的工廠方法創建,按照功能分類如下。
- 將流元素歸約和匯總為一個值
- 元素分組
- 元素分區
Stream的並行數據處理這部分暫時不提,其中涉及到並行流底層的實現,而且還有如何自定義的分割流,需要明白其原理才能正確的使用。這裏暫時先記住Stream可以透明的並行數據處理,提高程序效率。
默認方法
Java歷史已經很久了,但是目前為了讓集合支持Stream接口,我們需要針對集合提供一個stream的方法,但是已有很多的第三方庫實現了Collection接口,如果貿然在接口中添加方法,則會破壞向前兼容的屬性。所以Java8提供了默認方法,能夠保持向前兼容。
- Java8允許在接口內聲明靜態方法
- Java8引入的默認方法,可以指定接口方法的默認實現(返回類型之前使用default修飾)
但是默認方法的引入在某些情況下會引入一些沖突,類似C++多繼承中的菱形繼承問題,這裏Java8有一個解決沖突的規則,
- 類中的方法優先級最高。類或父類中聲明的方法優先級高於任何聲明為默認方法的優先級
- 如果無法依據第一條進行判斷,那麽子接口的優先級更高:函數簽名相同時,優先選擇擁有最具體實現的默認方法的接口,即如果B繼承了A,那麽B就比A更加具體
- 最後,如果還是無法判斷,繼承了多個接口的類必須通過顯式覆蓋和調用期望的方法顯式地選擇使用哪一個默認方法實現
Optional
Optional就是防止NullPointerException的出現而存在的一個特性,其實它在語義方面給予我們更多更多的代碼可讀性,設想當一個類的屬性使用Optional進行包裝,使用這個屬性的人就可以了解到這個屬性可能為null值,使用的時候就會小心謹慎,但是當一個屬性沒有使用Optional包裝,也就是說我可以放心的使用該引用,而不需要擔心NullPointerException。但是這需要一個team的約定。
Optional也可以在某些需要判定引用是否為null的地方去除if else判斷來使得代碼更加簡潔。
CompletableFuture
這個接口使得靈活的完成組合式的異步編程,是針對Future接口進一步的功能增強,但是相對於RxJava這種異步編程庫,其語義還是差一些,不過還是可以了解一下的。
新的日期和時間API
Java8解決的另外一個重要問題是解決之前老版本Java中java.util.Date
類以及其他用於建模日期時間類設計上的缺陷(易變性、糟糕的偏移值、默認值和命令)
關於Java中日期時間的操作,以後盡量使用java.time
包下的幾個新的類,包含LocalDate
, LocalTime
, Instant
, Duration
和Period
。
Java不斷的革新自己使得自己適應現在的編程場景,作為一名技術人員當然也需要不斷的更新自己的知識,保證自己也不斷的跟隨著浪潮前進。
Java的演化-Java8實戰筆記