《java8 in action》讀書筆記
語言需要不斷改進以跟進硬件的更新或滿足程序員的期待。所以java也需要演變,不然就會不適應IT產業的發展從而被別的語言淘汰,java語言現在更新到java12,不過業界主流應該還是java7或java8。
Java8中的主要變化反映了它開始遠離常側重改變現有值的經典面向對象思想,而向函數式編程領域轉變。在大面上考慮做什么被認為是頭等大事,并和如何實現區分開來。
行為參數化
簡單講就是把代碼通過參數傳遞給方法
- Lambda:直接傳方法中的代碼。
- 方法引用:把方法名作為參數傳遞,其實傳遞的是方法中的代碼,比lambda可讀性好。
Lambda
沒有名稱,但有參數列表、函數主體、返回類型,通過一個特殊的箭頭(->)把參數列表和函數主題分開。
lambda可以賦給函數式接口,函數式接口就是只定義了一個抽象方法的接口,lambda就是這個抽象方法的實現。
lambda中可以沒有限制的捕獲實例變量和靜態變量,但局部變量只能捕獲一次。而且要把局部變量聲明成final或者當final變量使用。原因是實例變量存儲在堆上,局部變量存在于棧上,而lambda是在一個線程中使用的,lambda線程可能會在分配該局部變量的線程把變量收回之后訪問它。因此,Java在訪問局部變量時,實際上是在訪問它 的副本,而不是訪問原始變量,如果該變量只賦值一次,副本和原始值沒區別的。
任何lambda都不允許拋出受檢異常,如果需要lambda表達式來拋出異常,可以定義一個自己的函數式接口或者把lambda放到try/catch中。
方法引用
方法引用的類類別:
1. 指向靜態方法的方法引用, 比如Integer::parseInt。
2. 指向任意類型實例方法的方法引用,引用一個對象的方法,這個對象本身是lambda的一個參數。比如(String s) -> s.toUppeCase(),可以寫成 String::toUppeCase
3. 指向現有對象的實例方法的方法引用。在lambda的函數體中調用一個已存在對象的方法,對象名::方法名。
流處理
流就是從支持數據處理操作的源生成的元素序列,流處理的出現順應了多核處理機的新時代,方便java進行并行處理。java的Synchronized在多核CPU上的執行成本比想象中的要高,多核處理器的每個內核都有獨立的高速緩存,加鎖需要這些高速緩存同步運行,然而這又需要在內核間進行較慢的緩存一致性協議通信。可以把流看作一個天然可并行的迭代器,同時加了類似linux管道操作的能力,可以一次迭代對集合中的數據進行多種有序處理,而且處理是可以利用多個cpu的并行處理,而且實現起來非常透明,幾乎免費,比搞Thread更簡單。流處理同時也是延后執行的,跟spark的迭代設計一致,都是由collection,reduce等action算子統一觸發之前的操作定義。
流處理的并行能力相應的也產生了一些限制:代碼無法訪問共享的可變數據。通過參數傳給流的方法都是無狀態函數或者叫純函數,不會改變某個共享的局部或全局對象。
收集器
收集器是為了收集流中的數據,對流做最終的歸約操作。流本身提供了collect接口,可以通過java.util.stream.collectors中的各種靜態工廠方法把流歸約成需要的數據結構。
默認方法
是為了讓庫設計師可以更容易的改進接口。簡而言之,在接口中定義一個方法同時在接口中實現,不用接口的繼承類做任何改變。如若不然,新增一個接口,已存在的類都得去做實現,會讓人瘋掉。
Optional<T>
避免NPE,變量存在時Optional類只是對類進行簡單的封裝,變量不存在時返回一個空的Optional實例。空的Optional實例是一個真實存在的對象,避免返回Null。
在寫程序的過程中常用的一個Optional語法糖是提取對象中的某屬性的值,不用先判空,特別是在遇到層次很深的屬性,非常方便。
person.flatMap(Person::getCar)
.flatMap(Car::getInsurance)
.map(Insurance::getName)
.orElse("Unknown");
用Optional聲明的對象無法實現序列化,這個是java8設計的時候沒讓Optional類繼承Serializable接口。
CompletableFuture
CompleteableFuture是對Future異步編程對升級,采用類似流處理的方式,把業務實現,通常是IO請求,如何響應IO請求結果流式的聲明出來,并通過靜態的接口進行觸發。
public Stream<CompletableFuture<String>> findPricesStream(String product) {
return shops.stream()
.map(shop -> CompletableFuture.supplyAsync(() -> shop.getPrice(product), executor))
.map(future -> future.thenApply(Quote::parse))
.map(future -> future.thenCompose(quote -> CompletableFuture.supplyAsync(() -> Discount.applyDiscount(quote), executor)));
}
CompletableFuture[] futures = findPricesStream("myPhone")
.map(f -> f.thenAccept(System.out::println))
.toArray(size -> new CompletableFuture[size]);
CompletableFuture.allOf(futures).join();
java8的日期和時間API
本意是為了簡化Java8之前Date和CalendarAPI的混亂,可是引入了新的LocalDate, LocalTime, LocalDateTime感覺更混亂了,并且LocalDate不能很方便的轉成Date, 對兼容老代碼并不友好。

浙公網安備 33010602011771號