我的感悟: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