java8在2014年就推出了,成天喊着8版本穩定,企業都用jdk8,結果8的特性如今才系統的學,罪過罪過啊!此係列博客可能3-4篇,帶你全面地瞭解java8新特性。java
其實我日常學習的時候看某些入門博客,總擔憂寫的不全,因此但願本身之後寫的技術博客可以把必須的儘量全的總結出來,作到看一篇就可以入門的水平。app
入門最快就是看demo啦,如今有個需求,讓你在衆多蘋果中挑選出紅色的蘋果ide
蘋果類函數
public class Apple { String color; int weight; //省略構造函數,get方法 }
public static List<Apple> filterGreenAppleWithNormal(List<Apple> apples) { List<Apple> res = new ArrayList<>(); for (Apple apple : apples) { if ("red".equals(apple.getColor())) { res.add(apple); } } return res; } //調用 List<Apple> normal = filterGreenAppleWithNormal(apples);
若是再有一個需求說挑選出綠色的蘋果呢,按照這種寫法就須要建立一個新的類,而後僅僅把"red"
修改爲"green"
其它都不變,這明顯是不顯示的。因此能夠把顏色當成參數傳進去學習
public static List<Apple> filterGreenAppleWithArg(List<Apple> apples, String color) { List<Apple> res = new ArrayList<>(); for (Apple apple : apples) { if (color.equals(apple.getColor())) { res.add(apple); } } return res; } //調用 List<Apple> arg = filterGreenAppleWithArg(apples, "red");
此時再有一個需求,須要篩選出必定重量或者某個顏色的蘋果,須要怎麼辦呢,按照上述想法是把能想到的屬性都堆到方法的參數中。ui
public static List<Apple> filterWeightOrColorWithArg(List<Apple> apples, String color, int weight, boolean flag) { List<Apple> res = new ArrayList<>(); for (Apple apple : apples) { if (flag && color.equals(apple.getColor()) || !flag && apple.getWeight() > weight) { res.add(apple); } } return res; } //調用 List<Apple> weightOrColor = filterWeightOrColorWithArg(apples, "", 500, false);
能夠這樣寫嗎,固然能夠解決問題,可是若是有5個屬性呢,6個屬性呢,還有,參數中的flag是什麼意思呢。idea
仔細一想,篩選顏色,篩選重量,這些的本質是在篩選,是一個行爲(後面更專業稱謂語),能夠把行爲抽象成一個接口 。spa
public interface AppleFilter { boolean filter(Apple apple); }
首先須要實現這個接口來具體化行爲code
public class RedFilter implements AppleFilter { @Override public boolean filter(Apple apple) { return "red".equals(apple.getColor()); } }
回到使用orm
public static List<Apple> filterApples(List<Apple> apples, AppleFilter filter) { List<Apple> res = new ArrayList<>(); for (Apple apple : apples) { if (filter.filter(apple)) { res.add(apple); } } return res; } //調用 List<Apple> behavior = filterApples(apples, new GreenFilter());
這樣看就舒服多了,當有新需求的時候,只須要再添加一個類,好比需求是篩選出重量超200g的蘋果,只須要新建一個篩選類實現上述接口便可。
public class WeightGt200Filter implements AppleFilter { @Override public boolean filter(Apple apple) { return apple.getWeight() > 200; } }
還能怎樣精簡代碼呢?熟悉Java的小夥伴到這裏應該就想到了匿名內部類
List<Apple> innerClass = filterApples(apples, new AppleFilter() { @Override public boolean filter(Apple apple) { return "green".equals(apple.getColor()); } });
通常到這一步,比較不錯的IDE就會開始提醒建議了
這就到了咱們今天的重點,lambda表達式
List<Apple> lambda = filterApples(apples, apple -> apple.getWeight() > 500);
沒錯,就是這麼精簡,不過filterApples
這個方法是不能省略的,可是擴展性相較1,2,簡潔性相較3,4都好了不少
能夠把Lamdba表達式理解爲簡潔地表示可傳遞的匿名函數的一種形式:它沒有名稱,但它有 參數列表、函數主題、返回類型,可能還有一個能夠拋出的異常列表
書寫格式: (參數) -> {主體}
正如上面寫法5同樣(apple) -> {apple.getWeight() > 500;}
使用案例:
() -> {}
() -> "java"
() -> {return "java";}
(int a, int b) -> a * b
() -> {System.out.println("hello"); System.out.println("java");}
使用 函數式接口的時候才能使用lambda表達式
所謂函數式接口就是僅僅定義了一個抽象方法,好比一開始把行爲抽象成一個AppleFilter
接口,該接口只有一個filter()
方法。注意是隻有一個抽象方法,並非只有一個方法,通俗來講是繼承該接口的類只須要實現一個方法。
最多見的兩個接口是Comparator
和Runnable
後來爲了更方便地區分函數式接口,Java新的API中多了一個@FuntionalInterface
,該註解僅僅是代表該類是函數式接口(並非必須的),若是有該註解的同時聲明瞭兩個抽象方法,那麼將會報錯
java.util.function
下主要有4個經常使用的函數式接口,Function
,Predicate
,Consumer
,Predicate
,隨便截取其中的一個源碼片斷來看,其實也沒啥好看的
對這些函數式接口也是得看接口是如何聲明的,這裏就拿Predicate
舉例,該接口主要是對傳進來的對象進行一個處理,而後返回boolean
值。是否是有點熟悉,沒錯,就是和篩選蘋果同樣
predicateDemo
public static List<Apple> predicateDemo(List<Apple> apples, Predicate<Apple> predicate) { List<Apple> res = new ArrayList<>(); for (Apple apple : apples) { if (predicate.test(apple)) { res.add(apple); } } return res; } //調用 List<Apple> predicate = predicateDemo(apples, apple -> "green".equals(apple.getColor()));
其餘的也是同理,上才藝
functionDemo
public static List<Integer> functionDemo(List<Integer> nums, Function<Integer, Integer> function) { List<Integer> res = new ArrayList<>(); for (int num : nums) { res.add(function.apply(num)); } return res; } //調用 List<Integer> function = functionDemo(Arrays.asList(1, 8, 7, 3, 9, 2), (num) -> num * 2);
consumerDemo
public static void consumerDemo(List<Integer> list, Consumer<Integer> consumer) { for (int num : list) { consumer.accept(num); } } //調用 consumerDemo(Arrays.asList(1, 5, 6), (num) -> System.out.println(num)); consumerDemo(Arrays.asList(1, 5, 6), System.out::println);
supplierDemo
public static void supplierDemo(List<Integer> nums, Supplier<String> supplier) { StringBuilder sb = new StringBuilder(); for (int num : nums) { sb.append(num).append(supplier.get()); } System.out.println(sb); } //調用 supplierDemo(Arrays.asList(1, 5, 6), ()->"java");
上面的lambda寫法是最精簡的嗎,不,不是的,還有最最最精簡的寫法,那就是利用方法引用
方法引用主要有3類:
Comparator<Integer> normalComparator = (a, b) -> a.compareTo(b); Comparator<Integer> referenceComparator = Integer::compareTo;
Function<String, Integer> normalFunction = (str) -> str.length(); Function<String, Integer> referenceFunction = String::length; BiPredicate<List<String>, String> normalPredicate = (strings, str) -> strings.contains(str); BiPredicate<List<String>, String> referencePredicate = List::contains;
Apple apple = new Apple(); Supplier<Integer> normal = () -> apple.getWeight(); Supplier<Integer> reference = apple::getWeight;
Supplier<Apple> normalSupplier = () -> new Apple(); Supplier<Apple> referenceSupplier = Apple::new;
以上就是java8中的lambda表達式,還有一些知識點是沒有講的,可是以爲不是特別必須,好比類型推斷是怎麼推斷的,還有Lambda複合,拋出異常,拆箱裝箱一樣沒有講。而後一些東西也不是全盤托出,須要各位小夥伴去idea中進入到源碼觀看。