公子奇帶你一步一步瞭解Java8中Lambda表達式

上一篇《公子奇帶你一步一步瞭解Java8中行爲參數化》中,咱們演示到最後將匿名實現簡寫爲html

1 (Police police) -> "浙江".equals(police.getPoliceNativePlace());

這是一個帶有箭頭的函數,這種寫法在Java8中即爲Lambda表達式。那麼咱們就來好好的講講Lambda表達式。java

一 、什麼是Lambda表達式

首先咱們須要知道Lambda表達式時JDK8中提出的編碼風格,它能夠簡潔地表示可做爲參數傳遞的匿名函數的一種方式,也能夠理解爲匿名實現的一種,關於匿名對象的特徵它也是有的,例如:它沒有名稱,但它有參數列表、函數主體、返回類型,可能還有一個能夠拋出的異常列表。基本語法可使用如下兩種方式表示:express

1 (parameters) -> expression 
2 3 (parameters) -> { statements; }

由上可知Lambda表達式有三個部分:app

一、參數列表ide

二、箭頭 「 -> 」 用來將參數和主體鏈接到一塊兒函數

三、Lambda主體ui

如下咱們經過一些案例來表示一個有效的Lambda表達式編碼

1 () -> "ABC";  //沒有參數但有返回值ABC,return 關鍵字自動忽略
2 () -> {};     //沒有參數,方法體不執行任何操做
3 () -> {return "ABC"}; //沒有參數,返回ABC,有大括號,須要顯示return
4 (String s) -> s.length(); //有一個參數,並對參數進行操做
5 (int x, int y) -> {       //有兩個參數,並作複雜操做,須要大括號
6     System.out.println("result:");
7     System.out.println(x + y);
8 }
9 (String s1, String s2) -> s1.compareTo(s2) //對兩個參數操做

2、什麼是函數式接口

上一篇文章中,咱們最後的Lambda表達式是做爲一個參數傳遞給filter方法的,同時在filter方法中的第二個參數是一個接口Predicate<T>,這個接口在JDK8中咱們就將其稱爲函數式接口,回看這個接口只有一個抽象方法。即函數式接口就是隻定義一個抽象方法的接口。同時在JDK8中也使用了註解 @FunctionInterface 將一個接口標註爲函數式接口,固然沒有添加該註解也可爲函數式接口,只是添加後程序在運行時會進行檢測,不然會拋出異常。同時爲了實現更靈活的操做,接口中能夠添加靜態方法和默認方法(即JDK8以後,接口中是能夠定義方法實現的)。spa

 1 package com.hz;
 2 
 3 /**
 4  * 在1.8以前,咱們一直強調接口中不可有方法實現
 5  * 1.8以後是能夠在接口中定義默認方法和靜態方法
 6  */
 7 public interface InterfaceMethod {
 8 
 9     default void method1() {
10         System.out.println("接口的默認方法實現...");
11     }
12 
13     static void method2() {
14         System.out.println("接口的靜態方法實現...");
15     }
16 
17     public static void main(String[] args) {
18         InterfaceMethod.method2();
19 
20         new InterfaceMethod() {}.method1();
21     }
22 }
23 
24 //官方提供的一個函數式接口
25 package java.util.function;
26 
27 import java.util.Objects;
28 
29 @FunctionalInterface
30 public interface Predicate<T> {
31     boolean test(T t);
32 
33     default Predicate<T> and(Predicate<? super T> other) {
34         Objects.requireNonNull(other);
35         return (t) -> test(t) && other.test(t);
36     }
37 
38     default Predicate<T> negate() {
39         return (t) -> !test(t);
40     }
41 
42     default Predicate<T> or(Predicate<? super T> other) {
43         Objects.requireNonNull(other);
44         return (t) -> test(t) || other.test(t);
45     }
46 
47     static <T> Predicate<T> isEqual(Object targetRef) {
48         return (null == targetRef)
49                 ? Objects::isNull
50                 : object -> targetRef.equals(object);
51     }
52 }
53 
54 //說明:從官網的Predicate接口中咱們能夠發現除了多了註解和一些方法實現,與咱們上一講本身定義的Predicate接口很相似

3、爲何提出函數式接口

    可能到這裏你也發現了,既然Lambda表達式已經很簡潔的表達了實現,咱們爲何還須要引入函數式接口的概念呢?爲了簡化代碼和靈活運用,咱們提出了Lambda表達式的概念,Lambda表達式容許你直接之內聯的形式爲函數式接口的抽象方法提供實現,並把整個表達式做爲函數式接口的實例。由此便可理解:Lambda表達式是函數式接口的一種實現。code

    在JDK8中咱們會發現大部分函數式接口都添加了 @FunctionInterface 註解,但咱們不能僅僅理解爲只有添加了該註解的才爲函數式接口,咱們應該理解的是隻有一個抽象方法的接口才爲函數式接口。

4、應用場景

    既然Lambda表達式這麼好,那麼咱們應該在哪裏去使用呢?下面介紹一些經常使用的:

    一、列表循環操做

 1 package com.hz;
 2 
 3 import java.util.Arrays;
 4 import java.util.List;
 5 import java.util.function.Consumer;
 6 
 7 public class LambdaTest {
 8     public static void main(String[] args) {
 9         List<String> ss = Arrays.asList("gong", "zi", "qi", "666");
10 
11         //打印列表中每一個值長度
12         //---匿名實現
13         ss.forEach(new Consumer<String>() {
14             @Override
15             public void accept(String s) {
16                 System.out.println(s.length());
17             }
18         });
19         
20         System.out.println("------------------");
21         
22         //--遍歷取值
23         for (String s : ss) {
24             System.out.println(s.length());
25         }
26 
27         System.out.println("---------");
28 
29         //--Lambda表達式
30         ss.forEach((String s) -> System.out.println(s.length()));
31     }
32 }
33 //哪一種方式簡潔、容易理解很明顯

    二、事件監聽

 1 //監聽實現一
 2 Button button = new Button("提交");
 3 button.addActionListener(new ActionListener() {
 4     @Override
 5     public void actionPerformed(ActionEvent e) {
 6         System.out.println("用戶點擊了提交按鈕");
 7     }
 8 });
 9 
10 //監聽實現二
11 button.addActionListener(e -> {
12     System.out.println("用戶點擊了提交按鈕");
13 });

    三、函數式接口(回看上一篇文章)

    更多應用場景,咱們在後續文章中再整理。

5、引出方法引用

    咱們繼續回看上一篇,發如今最後調用表達式是何其的類似

1 Police police) -> police.getPoliceAge() > 30;
2 
3 System.out.println("---------------");
4 
5 (Police police) -> "浙江".equals(police.getPoliceNativePlace());

    那麼在JDK8中還能夠再次簡化嗎?答案是確定的,這就是方法引用。即

1 Police :: getPoliceAge;
2 String :: equals;

    方法引用的加入可讓咱們重複使用現有的方法定義,並像Lambda同樣傳遞它們。咱們同時可理解爲方法引用是針對僅僅涉及單一方法的Lambda的語法糖。

    那麼什麼狀況下,咱們能夠及如何構建方法引用?

      一、指向靜態方法的方法引用。

      二、指向任意類型實例方法的方法引用。

      三、指向現有對象的實例方法的方法引用。

6、複合Lambda表達式組裝

    在實際開發中,咱們不可能只操做一種或一個Lambda表達式,一個表達式的輸出可能會是另外一個表達式的輸入,兩個條件的同時知足(例如上一篇中籍貫爲浙江年齡大於30的民警),或多個條件只要有一個合適即命中(例如上一篇中籍貫爲浙江或年齡大於30的民警)等。如此咱們將其分爲3類。

    一、比較器複合

繼續回到上一篇文章,如何對民警年齡進行排列。

 1 public static void main(String[] args) {
 2     List<Police> polices = Arrays.asList(new Police("P001", "餘警官", 27, "浙江"),
 3             new Police("P002", "李警官", 32, "安徽"),
 4             new Police("P003", "程警官", 25, "安徽"),
 5             new Police("P004", "楊警官", 35, "浙江"),
 6             new Police("P005", "楊警官", 31, "上海"));
 7 
 8     polices.sort(comparing(Police :: getPoliceAge).reversed());
 9 
10     System.out.println("結果1: " + polices);
11 }

    二、謂詞複合

1 Predicate<Police> p = (Police police) -> police.getPoliceAge() > 30;
2 Predicate<Police> p2 = p.and((Police police) -> "浙江".equals(police.getPoliceNativePlace()));
3 List<Police> result = filter(polices, p2);
4 System.out.println(result);
5 
6 //固然 除了 and  還有 or方法

    三、函數複合

1 Function<Integer, Integer> f = x -> x + 1;
2 Function<Integer, Integer> g = x -> x * 2;
3 Function<Integer, Integer> h = f.andThen(g);
4 int result = h.apply(1);
5 System.out.println(result);

7、一個實例

    回到上一篇文章場景,將按照必定條件獲得的民警按照年齡、籍貫排序。

 1 package com.hz;
 2  
 3 import java.util.ArrayList;
 4 import java.util.Arrays;
 5 import java.util.List;
 6 import java.util.function.Predicate;
 7 
 8 import static java.util.Comparator.comparing;
 9 
10 public class PoliceMain {
11     public static void main(String[] args) {
12         List<Police> polices = Arrays.asList(new Police("P001", "餘警官", 27, "浙江"),
13                 new Police("P002", "李警官", 32, "安徽"),
14                 new Police("P003", "程警官", 25, "安徽"),
15                 new Police("P004", "楊警官", 35, "浙江"),
16                 new Police("P005", "張警官", 31, "上海"),
17                 new Police("P006", "王警官", 42, "浙江"),
18                 new Police("P007", "趙警官", 31, "浙江"),
19                 new Police("P008", "劉警官", 49, "浙江"),
20                 new Police("P009", "周警官", 32, "浙江"));
21 
22         //問題:找出籍貫爲浙江而且年齡大於30歲的民警或者籍貫爲安徽的民警,按照民警年齡排序,若年齡相同按照籍貫排序
23         Predicate<Police> p1 = (Police police) -> police.getPoliceAge() > 30;
24 
25         Predicate<Police> p2 = p1.and((Police police) -> "浙江".equals(police.getPoliceNativePlace()));
26 
27         Predicate<Police> p3 = p2.or((Police police) -> "安徽".equals(police.getPoliceNativePlace()));
28 
29         List<Police> result = filter(polices, p3);
30 
31         result.sort(comparing(Police :: getPoliceAge).thenComparing(Police :: getPoliceNativePlace));
32 
33         System.out.println("結果: " + result);
34     }
35 
36     static <T> List<T> filter(List<T> con, Predicate<T> p) {
37         List<T> result = new ArrayList<>();
38 
39         for (T e : con) {
40             if (p.test(e)) {
41                 result.add(e);
42             }
43         }
44 
45         return result;
46     }
47 
48 }
49 
50 // 以上方式須要咱們本身去定義一個filter方法  或按照如下方式
51 
52 package com.hz;
53 
54 import java.util.ArrayList;
55 import java.util.Arrays;
56 import java.util.List;
57 import java.util.function.Function;
58 import java.util.function.Predicate;
59 
60 import static java.util.Comparator.comparing;
61 
62 public class PoliceMain {
63     public static void main(String[] args) {
64         List<Police> polices = Arrays.asList(new Police("P001", "餘警官", 27, "浙江"),
65                 new Police("P002", "李警官", 32, "安徽"),
66                 new Police("P003", "程警官", 25, "安徽"),
67                 new Police("P004", "楊警官", 35, "浙江"),
68                 new Police("P005", "張警官", 31, "上海"),
69                 new Police("P006", "王警官", 42, "浙江"),
70                 new Police("P007", "趙警官", 31, "浙江"),
71                 new Police("P008", "劉警官", 49, "浙江"),
72                 new Police("P009", "周警官", 32, "浙江"));
73 
74         //問題:找出籍貫爲浙江而且年齡大於30歲的民警或者籍貫爲安徽的民警,按照民警年齡排序,若年齡相同按照籍貫排序
75         Predicate<Police> p1 = (Police police) -> police.getPoliceAge() > 30;
76 
77         Predicate<Police> p2 = p1.and((Police police) -> "浙江".equals(police.getPoliceNativePlace()));
78 
79         Predicate<Police> p3 = p2.or((Police police) -> "安徽".equals(police.getPoliceNativePlace()));
80 
81         Function<List<Police>, List<Police>> f = (List<Police> list) -> {
82             List<Police> temp = new ArrayList<>();
83             for (Police police : list) {
84                 if (p3.test(police)) {
85                     temp.add(police);
86                 }
87             }
88             return temp;
89         };
90 
91         List<Police> result = f.apply(polices);
92 
93         result.sort(comparing(Police :: getPoliceAge).thenComparing(Police :: getPoliceNativePlace));
94 
95         System.out.println("結果: " + result);
96     }
97 
98 }
相關文章
相關標籤/搜索