第一部分:1~3章 主要講了行爲參數化和Lambda表達式java
第二部分:4~7章 主要講了流的應用,包括流與集合差別,流的操做,收集器,注的並行執行git
第三部分:8~12章 主要講了怎樣用Java8引入的特性改善老代碼,Optional類和CompleteFuture及新的日期和時間API編程
第四部分:13~16章 主要講了函數式編程app
本文主要是對第一部分的筆記。ide
行爲參數化就是拿出一個代碼塊,把它準備好卻不去執行它。函數式編程
有個果農,有以下需求:函數
擴展一下:設計
傳統實現方案code
// 篩選綠色蘋果 public static List<Apple> filterGreenApples(List<Apple> inventory) { List<Apple> result = new ArrayList<>(); for (Apple apple : inventory) { if ("green".equals(apple.getColor())) { result.add(apple); } } return result; } // 可篩選任意顏色蘋果,把顏色做爲參數 public static List<Apple> filterGreenApplesByColor(List<Apple> inventory, String color) { List<Apple> result = new ArrayList<>(); for (Apple apple : inventory) { if (apple.getColor().equals(apple.getColor())) { result.add(apple); } } return result; } // 篩選不一樣重量的蘋果 public static List<Apple> filterGreenApplesByWeight(List<Apple> inventory, int weight) { List<Apple> result = new ArrayList<>(); for (Apple apple : inventory) { if (apple.getWeight() > weight) { result.add(apple); } } return result; } // 寫一個方法同時支持篩選顏色和重量 public static List<Apple> filterGreenApples(List<Apple> inventory, String color, int weight , boolean filterColorFlag) { List<Apple> result = new ArrayList<>(); for (Apple apple : inventory) { if ((filterColorFlag && apple.getColor().equals(color)) || (!filterColorFlag && apple.getWeight() > weight)) { result.add(apple); } } return result; }
使用對象傳遞行爲參數對象
interface ApplePredicate { // 一個返回boolea值的函數,把它稱爲謂詞 boolean test(Apple apple); } // 篩選綠色 public class AppleGreenColorPredicate implements ApplePredicate { @Override public boolean test(Apple apple) { return "green".equals(apple.getColor()); } } // 重量大於150 class AppleHeavyWeightPredicate implements ApplePredicate { @Override public boolean test(Apple apple) { return apple.getWeight() > 150; } } // 紅色且重量大於150 class AppleRedAndHeavyPredicate implements ApplePredicate { @Override public boolean test(Apple apple) { return "red".equals(apple.getColor()) && apple.getWeight() > 150; } } // 實現 public static List<Apple> filterApples(List<Apple> inventory, ApplePredicate p) { List<Apple> result = new ArrayList<>(); for (Apple apple : inventory) { if (p.test(apple)) { result.add(apple); } } return result; } public void test() { List<Apple> inventory = new ArrayList<>(); // 篩選綠色 filterApples(inventory, new AppleGreenColorPredicate()); // 重量大於150 filterApples(inventory, new AppleHeavyWeightPredicate()); // 紅色且重量大於150 filterApples(inventory, new AppleRedAndHeavyPredicate()); }
使用匿名類傳遞行爲參數
// 對選擇標準建模 interface ApplePredicate { // 一個返回boolea值的函數,把它稱爲謂詞 boolean test(Apple apple); } // 實現 public static List<Apple> filterApples(List<Apple> inventory, ApplePredicate p) { List<Apple> result = new ArrayList<>(); for (Apple apple : inventory) { if (p.test(apple)) { result.add(apple); } } return result; } public static void main(String[] args) { List<Apple> inventory = new ArrayList<>(); // 篩選綠色 filterApples(inventory, new ApplePredicate() { @Override public boolean test (Apple apple){ return "green".equals(apple.getColor()); } }); // 重量大於150 filterApples(inventory, new ApplePredicate() { @Override public boolean test (Apple apple){ return apple.getWeight() > 150; } }); // 紅色且重量大於150 filterApples(inventory, new ApplePredicate() { @Override public boolean test (Apple apple){ return "red".equals(apple.getColor()) && apple.getWeight() > 150; } }); }
使用Lambda表達式傳遞行爲參數
interface ApplePredicate { boolean test(Apple apple); } public static List<Apple> filterApples(List<Apple> inventory, ApplePredicate p) { List<Apple> result = new ArrayList<>(); for (Apple apple : inventory) { if (p.test(apple)) { result.add(apple); } } return result; } public static void main(String[] args) { List<Apple> inventory = new ArrayList<>(); // 篩選綠色 filterApples(inventory , (Apple apple) -> "green".equals(apple.getColor())); // 重量大於150 filterApples(inventory , (Apple apple) -> apple.getWeight() > 150); // 紅色且重量大於150 filterApples(inventory , (Apple apple) -> "red".equals(apple.getColor()) && apple.getWeight() > 150); }
在這裏小結一下:
在方案4的基礎上 將List類型抽象化
// 定義一個函數式接口 interface Predicate<T> { boolean test(T t); } // 定義一個調用函數式接口的方法 public static <T> List<T> filter(List<T> list, Predicate<T> p) { List<T> result = new ArrayList<>(); for (T e : list) { if (p.test(e)) { result.add(e); } } return result; } // 使用 public static void main(String[] args) { List<Apple> inventory = FakeDb.getApples(); List<Apple> redList = Filtering.filter(inventory , (Apple apple) -> "red".equals(apple.getColor())); List<String> nonEmptyList = filter(Arrays.asList("1", "", "2") , (String s) -> !s.isEmpty()); }
簡潔地表示可傳遞的匿名函數的一種方法。
下面是5個有效的Lambda表達式
// 1 參數是String s,返回值是int (String s) -> s.length() // 2 參數是Apple a,返回值是boolean (Apple a) -> a.getWeight() > 150 // 3 參數是int x,int y 沒有返回值 {}內放語句,怎樣區分語句與表達式 (int x, int y) -> { System.out.println("Result:"); System.out.println(x + y); } // 4 無參數,返回int () -> 42 // 5 參數是兩個Apple類型的變量,返回值是boolean (Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight())
函數式接口就是隻定義一個抽象方法的接口。
函數式接口的抽象方法的簽名基本上就是Lambda表達式的簽名,這種抽象方法叫作函數描述符
一個註解:@FunctionalInterface
,不是必須的,用於表示該接口會設計成一個函數式接口
Predicate 過濾掉列表中的空串
// 定義一個函數式接口 interface Predicate<T> { boolean test(T t); } // 定義一個調用函數式接口的方法 public static <T> List<T> filter(List<T> list, Predicate<T> p) { List<T> result = new ArrayList<>(); for (T e : list) { if (p.test(e)) { result.add(e); } } return result; } // 使用 public static void main(String[] args) { List<String> nonEmptyList = filter(Arrays.asList("1", "", "2") , (String s) -> !s.isEmpty()); }
Consumer 計算列表中的每一個元素的平方並輸出
@FunctionalInterface public interface Consumer<T> { void accept(T t); } public static <T> void forEach(List<T> list, Consumer<T> c) { for (T i : list) { c.accept(i); } } public static void main(String[] args) { forEach(Arrays.asList(1, 2, 3, 4), (Integer i) -> System.out.println(i * i)); }
Function 返回列表中每一個元素的長度
@FunctionalInterface public interface Function<T, R> { R apply(T t); } public static <T, R> List<R> map(List<T> list, Function<T, R> f) { List<R> result = new ArrayList<>(); for (T s : list) { result.add(f.apply(s)); } return result; } public static void main(String[] args) { List<Integer> result = map(Arrays.asList("1", "22", "333") , (String s) -> s.length()); }
List<Apple> l = new ArrayList<Apple>(); List<Apple> l = new ArrayList<>(); // Java編譯器根據Lambda出現的上下文來推斷Lambda表達式參數的類型 Predicate<Apple> p = (Apple a) -> 'red'.equals(a.getColor()) Predicate<Apple> p = a -> 'red'.equals(a.getColor())
主要爲了簡化代碼
方法引用,3種
List<String> strList = Arrays.asList("a", "b", "A", "B"); strList.sort((s1, s2) -> s1.compareToIgnoreCase(s2)); strList.sort(String::compareToIgnoreCase); // 等效的方法引用
構造函數引用
Supplier<Apple> c1 = Apple::new; // 指向Apply()構造函數 Apple a1 = c1.get(); Function<Integer, Apple> c2 = Apple::new; // 指向Apply(int weight)構造函數 Apple a2 = c2.apply(110); BigFunction<String, Integer, Apple> c3 = Apple::new; // 指向Apply(String color, Integer weight) Apple c3 = c3.apply("green", 110);
根據Apple的重量來排序
// 行爲參數化,下面是經過不一樣方式傳遞這個行爲的 // 1.使用對象 public class AppleComparator implements Comparator<Apple> { public int compare(Apple a1, Apple a2) { return a1.getWeight().compareTo(a2.getWeight()); } } inventory.sort(new AppleComparator()); // 2.使用匿名類 inventory.sort(new Comparator<Apple>(){ public int compare(Apple a1, Apple a2) { return a1.getWeight().compareTo(a2.getWeight()); } }); // 3.使用Lambda表達式 inventory.sort((Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight())); // 由於類型推斷,能夠簡化成 inventory.sort((a1, a2) -> a1.getWeight().compareTo(a2.getWeight())); // 由於有個java.util.Comparator.comparing靜態方法,還能夠簡化成 import static java.util.Comparator.comparing; inventory.sort(comparing((a) -> a.getWeight())); // 4.使用方法引用 inventory.sort(comparing(comparing(Apple::getWeight)));
比較器複合
// 逆序,蘋果按重量遞減排序 inventory.sort(comparing(Apple::getWeight).reversed()); // 比較器鏈,先按重量遞減排序再按國家排序 inverntory.sort(comparing(Apple::getWeight).reversed() .thenComparing(Apple::getCountry));
謂詞複合
// negate,and,or // 篩選不是紅蘋果 Predicate<Apple> notRedApple = redApple.negate(); // 篩選紅蘋果且重量大於150 或 綠蘋果 redApple.and(a -> a.getWeight() > 150).or(a -> "green".equals(a.getColor())); // a.or(b).and(c) <==> (a || b) && c
函數複合
// andThen,compose Function<Integer, Integer> f = x -> x + 1; Function<Integer, Integer> g = x -> x * 2; // g(f(x)) Function<Integer, Integer> h = f.andThen(g); int result = h.apply(1); // f(g(x)) Function<Integer, Integer> h = f.compose(g); int result = h.apply(1);