《Java8實戰》讀書筆記

我的感悟:java

1.lambda表達式,補充了JAVA在面向對象以外,面向過程的一面。在寫面向過程代碼的時候更方面了,甚至能夠利用代碼來作相似數學公式的運算(P64)數據庫

2.流,對集合的操做,就像用SQL對數據表的操做那樣,屏蔽了實現,節約了開發時間(P68)express

3.流能夠處理集合,可是這2者是徹底不一樣的2個概念。集合是急切建立的,流則是按需生成(就像碟片播放和在線播放)(P74)編程

4.函數式編程相對於指令式編程的一個主要優點:你只需指出但願的結果——「作什麼」,而不用操心執行的步驟——「如何作」。(P112)設計模式

5.函數式編程(特別是Java 8的 Collections 框架中加入的基於函數式風格原 理設計的新API)一般提供了多種方法來執行同一個操做。(P119)數組

 

---------------2019-4-25筆記更新--------------安全

1.option要結合lambda表達式使用才美味,不要單獨使用數據結構

2.lambda表達式:匿名函數的一種簡潔的表達形式閉包

3.函數式接口:只定義一個抽象方法的接口(打上@FunctionalInterface標籤)app

PS.能夠在函數式接口上使用lambda表達式,使代碼的設計模式更優雅

4.語法糖演進:接口實現類 -> 匿名類 -> lambda表達式 

5.類型推斷:java編譯器能夠經過上下文推斷出lambda表達式的參數類型,所以能夠省略 (有時候爲了代碼易讀性,也能夠顯示的寫類型)

6.方法引用:lambda的語法糖,如(Apple a) -> a.getWeight()能夠寫成Apple::getWeight

 

P53.lambda這一章很精彩。必定要仔細讀完!

---------------分割線--------------

 

1、基礎知識

1.從有點修正主義的角度來看,在Java 8中加入 Streams 能夠看做把另外兩項擴充加入Java 8 的直接緣由:把代碼傳遞給方法的簡潔方式(方法引用、Lambda)和接口中的默認方法。

2.Java 8裏面將代碼傳遞給方法的功能(同時也可以返回代碼並將其包含在數據結構中)還讓 咱們可以使用一整套新技巧,一般稱爲函數式編程。

3.Java 8提供了一個新的API(稱爲「流」,Stream),它支持許多處理數據的並行操做,其思路 和在數據庫查詢語言中的思路相似——用更高級的方式表達想要的東西,而由「實現」(在這裏 是Streams庫)來選擇最佳低級執行機制。

4.這兩個要點(沒有共享的可變數據,將方法和函數即代碼傳遞給其餘方法的能力)是咱們日常所說的函數式編程範式的基石

5.若是極端點兒來講,傳統的面向對象編程和函數式可能看起來是衝突的。可是咱們的理念是得到兩種編程範式中最好的東西,這樣你就有更大的機會爲任務找到理想的工具了

6.方法引用:讓方法做爲值 也構成了其餘若干Java 8功能(如 Stream )的基礎,編寫把函數做爲一等值來傳遞的程序。

7.有了Stream API,你根本用不着操心循環的事情。數據處 理徹底是在庫內部進行的。咱們把這種思想叫做內部迭代

8.Java中從函數式編程中引入的兩個核心思想:將方法和Lambda做爲一等值,以及在沒有可變共享狀態時,函數或方法能夠有效、安全地並行執行

9.匿名函數必需要傳一個對象進方法,而Lambda表達式能夠只關心方法

10.Lambda 的基本語法是 (parameters) -> expression 或 (parameters) -> { statements; }(請注意語句的花括號)。注意,表達式(expression )和語句(statements)不能互換。

11.函數式接口就是隻定義一個抽象方法的接口

12.有了目標類型的概念,同一個Lambda表達式就能夠與不一樣的函數式接口聯繫起來,只要它們的抽象方法簽名可以兼容。

13.Lambda有點像閉包。能夠認爲Lambda是對值封閉,而不是對變量封閉(局部變量必須爲final)。

14.當你須要使用方法引用時,目標引用放在分隔符 :: 前,方法的名稱放在後面

 

2、函數式數據處理

1.流的簡短的定義就是「從支持數據處理操做的源生成的元素序列」

2.集合講的是數據,流講的是計算

3.流只能消費一次(只能遍歷一次)

4.集合處理數據用外部迭代,而流用內部迭代(另外,for-eache是Iterator的語法糖)

5.中間操做通常均可以合併起來,在終端操做時一次性所有處理(效率更好,流中的元素是按需計算的)

6.flatmap 方法讓你把一個流中的每一個值都換成另外一個流,而後把全部的流鏈接 起來成爲一個流。

 

---------------分割線--------------

經常使用方法:

1、謂詞

1.filter():篩選

2.distinct():去重

3.limit():截斷

4.skip():跳過

2、映射

1.map():映射

2.flatmap():拍平,匯合

3、查找和匹配

1.allMatch 、 anyMatch 、 noneMatch 、 findFirst 和 findAny(這2個區別是並行和效率)

4、規約

1.reduce():規約

5、數值流

1.IntStream 、 DoubleStream 和 LongStream

2.mapToInt 、 mapToDouble 和 mapToLong

3.boxed()(裝箱,和上面操做相反)

4.OptionalInt 、 OptionalDouble 和 OptionalLong

5.Arrays.stream():從數組建立一個流

6、收集流

1.Collectors.toList()

2.Collectors.summingInt():求和

3.Collectors.summarizingInt():彙總(一樣還有summarizingLong 和 summarizingDouble )

4.collect(groupingBy(Lambda表達式)):分組

5.Collectors.collectingAndThen():分組,並返回指定類型(和上面那個方法對應,是上面方法的擴展)

6.groupingBy():分組

7.partitioningBy():分區

8.能夠自定義收集類:須要實現3-5個接口

7、並行流

8、重構、測試和調試

9、默認方法

1.相同函數簽名的繼承原則:

(1) 類中的方法優先級最高。類或父類中聲明的方法的優先級高於任何聲明爲默認方法的優先級。
(2) 若是沒法依據第一條進行判斷,那麼子接口的優先級更高:函數簽名相同時,優先選擇擁有最具體實現的默認方法的接口,即若是 B 繼承了 A ,那麼 B 就比 A 更加具體。
(3) 最後,若是仍是沒法判斷,繼承了多個接口的類必須經過顯式覆蓋和調用指望的方法,顯式地選擇使用哪個默認方法的實現。

10、用optional取代null

11、completeFuture

12、新的日期和時間API

十3、函數式的思考

十4、函數式編程的技巧

十5、面向對象和函數式編程的混合:Java和 Scala的比較

十6、結論以及Java的將來

X、其它

1.count():計算流的元素個數

---------------分割線--------------

經常使用示例代碼:

1)獲取list對象的內容合併成List:

  List<Long> childModuleIdList = childModuleList.stream().map(StudyModuleDO::getId).collect(Collectors.toList());

2)List轉Map:

  Map<Date, List<DailyStatusBO>> dateList = dailyStatusList.stream().collect(Collectors.groupingBy(DailyStatusBO::getDate)); //不去重

  Map<Integer, Student> map = list.stream().collect(Collectors.toMap(Student::getId, student -> student)); //去重

  返回對象自己的語法糖:Function.identity()

3) list轉set

  userIdList.stream().map(userIdAndBbsIdMap::get).collect(Collectors.toSet());

代碼示例:

1.List<Dish> vegetarianDishes = menu.stream() .filter(Dish::isVegetarian) .collect(toList());

2.List<String> uniqueCharacters = words.stream() .map(w -> w.split("")) .flatMap(Arrays::stream) .distinct() .collect(Collectors.toList());

3.int sum = numbers.stream().reduce(0, Integer::sum);

4.Optional<Integer> sum = numbers.stream().reduce((a, b) -> (a + b));(可能無值,因此用Optional接)

5.OptionalInt maxCalories = menu.stream() .mapToInt(Dish::getCalories) .max();

6.IntStream evenNumbers = IntStream.rangeClosed(1, 100) .filter(n -> n % 2 == 0);

7.Stream<String> stream = Stream.of("Java 8 ", "Lambdas ", "In ", "Action");

8.int totalCalories = menu.stream().collect(summingInt(Dish::getCalories));

9.String shortMenu = menu.stream().map(Dish::getName).collect(joining(", "));

10.Map<Dish.Type, List<Dish>> dishesByType = menu.stream().collect(groupingBy(Dish::getType));

11.Map<Dish.Type, Set<CaloricLevel>> caloricLevelsByType = menu.stream().collect( groupingBy(Dish::getType, mapping( dish -> { if (dish.getCalories() <= 400) return CaloricLevel.DIET; else if (dish.getCalories() <= 700) return CaloricLevel.NORMAL; else return CaloricLevel.FAT; }, toCollection(HashSet::new) )));(上面那個例子的複雜版)

----------------附錄---------------

P100:小練習,能夠用來熟悉lambda表達式

P104:小練習,能夠實現提取勾股數

P107:小練習,生成斐波納契數列

P128:小練習 將數字按質數和非質數分區

 

有用的東西:

1.Collectors類的靜態工廠方法列表:P128

相關文章
相關標籤/搜索