(個人筆記 水準有限 僅供參考)
我認為Java8中最重要的幾個改動:
1.Lambda表達式:(實作了把代碼傳給方法的方式,能夠少些代碼,而且可以實作解耦與代碼複用,而且看起來很有條理,而且提供了并行以及自定義收集器,而且進行資料的統計的時候非常友善)。
2.函數式程式設計(将函數作為資料自由傳遞,結合泛型推導的能力,包括函數式接口(Function/Supplier/Consumer/Predicate等)收集器(Reduce等)與Stream(流))
3.時間日期類的改進(LocalDateTime實在太好用了)
第一章:為什麼要關心Java8
1.在Java8中加入Streams可以看作另外兩項擴充加入Java8的直接原因:把代碼傳遞給方法的簡潔方式(方法引用,Lambda)和接口的預設方法。Streams實作了行為的參數化,隻需要把不同的那部分傳遞進去就可以了,比如計算數組中能被2整除的數的和以及能被3整除的數的和,如果傳遞進去的是一個Predicate對象的話,就能夠比使用政策模式更好用。
2.Java8裡面能夠将方法傳遞給代碼同時也能夠傳回代碼并将其包含在資料結構中,而且還能讓我們使用的一整套新技巧,被稱為函數式程式設計
3.一次編寫到處運作,Java的語言(Scala\Groovy)無關性與平台(作業系統層面)無關性。
4.流(A sequence of(一系列的) elements supporting sequential(順序) and parallel(并行) aggregate(聚合) operations)。流是一連串連續不繼的資料的集合,程式可以從流中讀取資料,也可以把資料放入流中,一個程式的輸出流也可能是另一個程式的輸入流。
5.用行為參數化把代碼傳遞給方法。直接傳遞lambda表達式和方法引用,将方法和lambda作為一等公民(就是程式設計中的重要角色,以前是值)。
6.并行與可共享的資料(純函數/無副作用的函數/無狀态函數),傳遞的方法無互動(比方說有可變的共享對象);
7.從側重改變現有現有值的面向對象思想變成函數式程式設計領域。
8.foreach(外部疊代)與Stream流的内部疊代
9.對集合的優化處理(需要在某些集合接口中增加新的方法,為了相容,增加了預設方法)。pipeline()
---Collection是一個集合類型,目的是為各種集合提供最大化的統一操作(default boolean removeIf(Predicate<? super E> filter) / pipeline(管道)(Abstract base class for "pipeline" classes, which are the core implementations of the Stream interface and its primitive(原始的) specializations(專業化). Manages construction and evaluation of stream pipelines),Collections則包裝類,封裝了關于集合的多元化操作。
public static <T> Stream<T> stream(Spliterator<T> spliterator, boolean parallel) {
Objects.requireNonNull(spliterator);
return new ReferencePipeline.Head<>(spliterator,
StreamOpFlag.fromCharacteristics(spliterator),
parallel);
}
關于Stream的專業分析見這裡:https://blog.csdn.net/zw19910924/article/details/77018798
10.關于Optional<T>的使用與模式比對機制。
第二章、通過行為參數化傳遞代碼
1.政策設計模式(定義一族算法然後封裝起來(稱為政策),然後在運作時選擇一個算法)。
2.簡單工廠方法(工廠->具體産品)/抽象工廠方法(多個産品族)/工廠方法(不同産品)
第三章、Lambda表達式
1.匿名/函數/傳遞/簡潔
2.函數式接口(@functionalinterface)/函數描述符(函數式接口的抽象方法的簽名基本上就是Lambda表達式的簽名,我們将這種方法叫做函數描述符,例如Runnable接口可以看作是一個什麼也不接受什麼也不傳回的函數簽名)。
3.環繞執行模式(try(BufferedReader br=new BufferedReader(new FileReader("data.txt")))){},這樣隻能夠讀取1行,如果2行,需要封裝成個processFile((BufferedReader br)->br.readLine()+br.readLine())--->是以需要自定義一個功能函數接口并且自主抛出異常(return p.process(br))。
4.幾個新的函數式接口:
1.Predicate test()方法 -->T->Boolean
2.Consume的accept()方法--->T->()
3.Supplier的get()方法--->()->T
4.Function的apply()方法----》将T轉換成R
5.UnaryOperator<T>--->extends Function(表示操作符,可用于計算)
6.BiFunction/BiPredicate/BinaryOperate(Extends BiFunction)(Bi表示接受兩個函數傳回1個)
5.泛型(僞泛型)+(泛型數組)+(泛型擦除(Object/邊界))+頻繁的拆裝箱(IntPredicate/LongPredicate(泛型特化))
6.任何函數式接口都不允許抛出受檢異常(異常分為Error與Exception,Exception分為運作時異常(RuntimeException及其子類)與非運作時異常(編譯異常,必須手動抛出捕獲異常,否則或報錯,如IOException與ClassNotFoundException)),是以需要lambda表達式來抛出異常的話 1.自己通過@FunctionalInterface來定義一個函數式接口,裡面定義的方法throws IOException和自己用try/catch來顯示定義異常。
7.類型檢查/類型推斷以及限制( Callable<Integer> c=()->42; PrivilegeAction<INteger> p=()->42;(Java的安全模型裡面的,用于某些具有優先級的判斷))。隻要函數式接口要求的類型轉換滿足,同一個Lambda表達式就可以作用于不同的函數式接口。Java7引入的菱形運算符,利用泛型推斷從上下文推斷類型的思想。(注:特殊的void相容:void可以相容是語句表達式的 如:Predicate<String> p=s->list.add(s) 和Consume<String> b=s->s.add(s));類型推斷是Lambda可以省略具體類型的基礎;
8.Lambda表達式可以沒有限制的捕獲執行個體變量和靜态變量,但局部變量有限制(必須顯示或者隐式的是final的),也就是隻能捕獲指派給他們的局部變量一次。(因為執行個體變量儲存在堆裡面,堆中可以共享,但局部變量儲存在棧裡面,而且隐式表明他們僅限于目前線程)。
9.方法引用 Comparator::comparing ArrayList::new 對構造函數進行引用 1個變量 supplier=Constructor::new get 2個變量用function=ConStruction::new apply 3個變量的話可以自己構造可以接受3個變量的Function函數。
10.Lambda表達式的複合(多個Lambda表達式複合成複雜的表達式); 1.比較器複合 Comparing.thenComparing 2.謂詞複合and or(從左到右确定優先級)3.函數複合 f.andThen(g)--g(f(x)) f.compose(g)--f(g(x))
第四章、引入流
1.流是一段連續不繼的資料的集合。能夠減少垃圾變量以及能夠并行的運作代碼。
2.注意groupingBy()方法的運用:
public static <T, K> Collector<T, ?, Map<K, List<T>>> groupingBy(Function<? super T, ? extends K> classifier){
return groupingBy(classifier, toList());}
public interface Collector<T, A, R>
T:表示流中每個元素的類型 A:表示中間結果容器的類型。R:表示最終傳回的結果類型