1. 程式人生 > 實用技巧 >Java1.8之Lambda表示式

Java1.8之Lambda表示式

1、Java8的lambda表示式,通過lambda表示式可以替代我們之前寫的匿名內部類來實現介面。lambda表示式本質是一個匿名函式。

 1 package com.demo.main;
 2 
 3 public class LambdaMain {
 4 
 5     public static void main(String[] args) {
 6 
 7         // 1、建立一個匿名內部類
 8         Addition addition = new Addition() {
 9 
10             @Override
11             public
int add(int a, int b) { 12 13 return a + b; 14 } 15 16 }; 17 // 傳統的匿名內部類來實現介面。 18 System.out.println("呼叫匿名內部類來實現介面:" + addition.add(2, 3)); 19 20 // 2、Java8的lambda表示式,通過lambda表示式可以替代我們之前寫的匿名內部類來實現介面。 21 // lambda表示式本質是一個匿名函式。 22 //
2.1、lambda由三部分組成,()是引數列表,->剪頭符號,{}代表方法體。 23 Addition a2 = (int a, int b) -> { 24 return a + b; 25 }; 26 System.out.println("lambda表示式a2:" + a2.add(3, 3)); 27 28 // 2.2、可以省略引數列表裡面的引數型別 29 Addition a3 = (a, b) -> { 30 return a + b;
31 }; 32 System.out.println("lambda表示式a3:" + a3.add(3, 3)); 33 34 } 35 36 /** 37 * 38 * @author 建立一個介面,定義一個方法 39 * 40 */ 41 interface Addition { 42 43 /** 44 * 加法的方法 45 * 46 * @param a 47 * @param b 48 * @return 49 */ 50 int add(int a, int b); 51 } 52 53 }

2、Lambda表示式語法,形如(int a, int b) -> {return a + b;},lambda本質就是一個(匿名)函式,匿名函式,就是沒有方法名稱的函式。

1 一般函式結構類似,如下所示:
2 int add(int a, int b){
3     return  a + b;
4 }
5 
6 一般函式的,結構如:返回值 方法名稱(引數列表) 方法體。

3、而Lamdba表示式函式,只有引數列表和方法體。結構如:(引數列表) -> {方法體};

詳細說明,如下所示:

  1)、()括號用來描述引數列表。
  2)、{}大括號用來描述方法體。
  3)、->尖括號,Lambda運算子,可以叫做箭頭符號,或者goes to。

4、Lambda表示式語法,關於介面方法引數、無參、單個引數、兩個引數、有返回值、沒有返回值的情況。如何來根據lambda來返回介面函式。

  1 package com.demo.main;
  2 
  3 public class LambdaMain {
  4 
  5     public static void main(String[] args) {
  6         // 1、無引數無返回值
  7         MethodNoReturnNoParam methodNoReturnNoParam = () -> {
  8             System.out.println("無引數無返回值");
  9         };
 10         methodNoReturnNoParam.lambda1();
 11 
 12         // 2、單個引數無返回值
 13         MethodNoReturnOneParam methodNoReturnOneParam = (int a) -> {
 14             System.out.println("單個引數無返回值,a = " + a);
 15         };
 16         methodNoReturnOneParam.lambda2(3);
 17 
 18         // 3、兩個引數無返回值
 19         MethodNoReturnTwoParam methodNoReturnTwoParam = (int a, int b) -> {
 20             System.out.println("兩個引數無返回值,a + b = " + (a + b));
 21         };
 22         methodNoReturnTwoParam.lambda3(3, 4);
 23 
 24         // 4、無引數有返回值
 25         MethodReturnNoParam methodReturnNoParam = () -> {
 26             return 8;
 27         };
 28         System.out.println("無引數有返回值:" + methodReturnNoParam.lambda4());
 29 
 30         // 5、一個引數有返回值
 31         MethodReturnOneParam methodReturnOneParam = (int a) -> {
 32             return a;
 33         };
 34         System.out.println("一個引數有返回值,a = " + methodReturnOneParam.lambda5(9));
 35 
 36         // 6、一個引數有返回值
 37         MethodReturnTwoParam methodReturnTwoParam = (int a, int b) -> {
 38             return a + b;
 39         };
 40         System.out.println("一個引數有返回值,a + b = " + methodReturnTwoParam.lambda6(9, 9));
 41 
 42     }
 43 
 44     /**
 45      * 1、無引數無返回值
 46      * 
 47      * @author
 48      *
 49      */
 50     interface MethodNoReturnNoParam {
 51 
 52         void lambda1();
 53     }
 54 
 55     /**
 56      * 2、單個引數無返回值
 57      * 
 58      * @author
 59      *
 60      */
 61     interface MethodNoReturnOneParam {
 62 
 63         void lambda2(int a);
 64     }
 65 
 66     /**
 67      * 3、兩個引數無返回值
 68      * 
 69      * @author
 70      *
 71      */
 72     interface MethodNoReturnTwoParam {
 73 
 74         void lambda3(int a, int b);
 75     }
 76 
 77     /**
 78      * 4、無引數有返回值
 79      * 
 80      * @author
 81      *
 82      */
 83     interface MethodReturnNoParam {
 84 
 85         int lambda4();
 86     }
 87 
 88     /**
 89      * 5、一個引數有返回值
 90      * 
 91      * @author
 92      *
 93      */
 94     interface MethodReturnOneParam {
 95 
 96         int lambda5(int a);
 97     }
 98 
 99     /**
100      * 6、兩個引數有返回值
101      * 
102      * @author
103      *
104      */
105     interface MethodReturnTwoParam {
106 
107         int lambda6(int a, int b);
108     }
109 
110 }

5、Lambda表示式語法,精簡寫法,如下所示:

  1)、引數型別可以省略。
  2)、假如只有一個引數,()括號可以省略。
  3)、如果方法體只有一條語句,{}大括號可以省略。
  4)、如果方法體中唯一的語句是return返回語句,那省略大括號的同時return關鍵詞也要省略掉。

 1 package com.demo.main;
 2 
 3 public class LambdaMain {
 4 
 5     public static void main(String[] args) {
 6         // 1、無引數無返回值
 7         MethodNoReturnNoParam methodNoReturnNoParam = () -> System.out.println("無引數無返回值");
 8         methodNoReturnNoParam.lambda1();
 9 
10         // 2、單個引數無返回值
11         MethodNoReturnOneParam methodNoReturnOneParam = a -> System.out.println("單個引數無返回值,a = " + a);
12         methodNoReturnOneParam.lambda2(3);
13 
14         // 3、兩個引數無返回值
15         MethodNoReturnTwoParam methodNoReturnTwoParam = (a, b) -> System.out.println("兩個引數無返回值,a + b = " + (a + b));
16         methodNoReturnTwoParam.lambda3(3, 4);
17 
18         // 4、無引數有返回值
19         MethodReturnNoParam methodReturnNoParam = () -> 8;
20         System.out.println("無引數有返回值:" + methodReturnNoParam.lambda4());
21 
22         // 5、一個引數有返回值
23         MethodReturnOneParam methodReturnOneParam = a -> a + 10;
24         System.out.println("一個引數有返回值,a = " + methodReturnOneParam.lambda5(9));
25 
26         // 6、一個引數有返回值
27         MethodReturnTwoParam methodReturnTwoParam = (a, b) -> a + b;
28         System.out.println("一個引數有返回值,a + b = " + methodReturnTwoParam.lambda6(9, 9));
29 
30     }
31 
32     /**
33      * 1、無引數無返回值
34      * 
35      * @author
36      *
37      */
38     interface MethodNoReturnNoParam {
39 
40         void lambda1();
41     }
42 
43     /**
44      * 2、單個引數無返回值
45      * 
46      * @author
47      *
48      */
49     interface MethodNoReturnOneParam {
50 
51         void lambda2(int a);
52     }
53 
54     /**
55      * 3、兩個引數無返回值
56      * 
57      * @author
58      *
59      */
60     interface MethodNoReturnTwoParam {
61 
62         void lambda3(int a, int b);
63     }
64 
65     /**
66      * 4、無引數有返回值
67      * 
68      * @author
69      *
70      */
71     interface MethodReturnNoParam {
72 
73         int lambda4();
74     }
75 
76     /**
77      * 5、一個引數有返回值
78      * 
79      * @author
80      *
81      */
82     interface MethodReturnOneParam {
83 
84         int lambda5(int a);
85     }
86 
87     /**
88      * 6、兩個引數有返回值
89      * 
90      * @author
91      *
92      */
93     interface MethodReturnTwoParam {
94 
95         int lambda6(int a, int b);
96     }
97 
98 }

6、方法引用,如果多個lamdba表示式實現函式都是一樣的話,可以封裝成通用方法,以方便維護,此時可以使用方法引用實現。

  語法規則:物件::方法。假如是static靜態方法,可以直接類名::方法。

 1 package com.demo.main;
 2 
 3 public class LambdaMain {
 4 
 5     public static void main(String[] args) {
 6 //        // 建立物件
 7 //        LambdaMain lambdaMain = new LambdaMain();
 8 //        // 採用物件引用的方式進行實現
 9 //        MethodReturnOneParam methodReturnOneParam_1 = lambdaMain::add;
10 //        System.out.println(methodReturnOneParam_1.lambda5(10));
11 //
12 //        // 採用物件引用的方式進行實現
13 //        MethodReturnOneParam methodReturnOneParam_2 = lambdaMain::add;
14 //        System.out.println(methodReturnOneParam_2.lambda5(40));
15         
16         
17         // 建立物件
18         // 採用靜態物件引用的方式進行實現
19         MethodReturnOneParam methodReturnOneParam_1 = LambdaMain::addStatic;
20         System.out.println(methodReturnOneParam_1.lambda5(10));
21 
22         // 採用靜態物件引用的方式進行實現
23         MethodReturnOneParam methodReturnOneParam_2 = LambdaMain::addStatic;
24         System.out.println(methodReturnOneParam_2.lambda5(40));
25     }
26 
27     /**
28      * 方法引用,如果多個lamdba表示式實現函式都是一樣的話,可以封裝成通用方法,以方便維護,此時可以使用方法引用實現。
29      * 
30      * @param a
31      * @return
32      */
33     public int add(int a) {
34         return a + 10;
35     }
36 
37     /**
38      * 靜態方法引用
39      * 
40      * @param a
41      * @return
42      */
43     public static int addStatic(int a) {
44         return a + 10;
45     }
46 
47     /**
48      * 5、一個引數有返回值
49      *
50      * @author
51      *
52      */
53     interface MethodReturnOneParam {
54 
55         int lambda5(int a);
56     }
57 
58 }

7、構造方法引用,如果函式式介面的實現切好可以通過呼叫一個類的構造方法來實現,那麼就可以使用構造方法引用。

語法規則:類名::new。

 1 package com.demo.po;
 2 
 3 public class Dog {
 4 
 5     private String name;
 6     private int age;
 7 
 8     public String getName() {
 9         return name;
10     }
11 
12     public void setName(String name) {
13         this.name = name;
14     }
15 
16     public int getAge() {
17         return age;
18     }
19 
20     public void setAge(int age) {
21         this.age = age;
22     }
23 
24     @Override
25     public String toString() {
26         return "Dog [name=" + name + ", age=" + age + "]";
27     }
28 
29     public Dog(String name, int age) {
30         System.out.println("含參建構函式!");
31         this.name = name;
32         this.age = age;
33     }
34 
35     public Dog() {
36         System.out.println("無參建構函式!");
37     }
38 
39 }

 1 package com.demo.main;
 2 
 3 import com.demo.po.Dog;
 4 
 5 public class LambdaMain {
 6 
 7     public static void main(String[] args) {
 8         // 1、使用lambda表示式的方式使用
 9         DogService dogService1_0 = () -> {
10             return new Dog();
11         };
12         dogService1_0.getDog();
13 
14         // 2、簡化方式
15         DogService dogService1_1 = () -> new Dog();
16         dogService1_1.getDog();
17 
18         // 3、構造方法引用,如果函式式介面的實現切好可以通過呼叫一個類的構造方法來實現,那麼就可以使用構造方法引用。
19         DogService dogService1_2 = Dog::new;
20         dogService1_2.getDog();
21 
22         // 4、構造方法引用,有參建構函式呼叫
23         DogService2 dogService2_1 = Dog::new;
24         dogService2_1.getDog("小黃", 2);
25 
26     }
27 
28     interface DogService {
29 
30         /**
31          * 獲取到一隻無名狗
32          * 
33          * @return
34          */
35         Dog getDog();
36     }
37 
38     interface DogService2 {
39 
40         /**
41          * 獲取到一個有名稱的狗
42          * 
43          * @param name
44          * @param age
45          * @return
46          */
47         Dog getDog(String name, int age);
48     }
49 
50 }

8、集合使用lambda表示式對資料進行排序,遍歷等操作。對於引數是介面函式的方法,需要傳遞lamdba表示式作為引數進行呼叫。

 1 package com.demo.main;
 2 
 3 import java.util.ArrayList;
 4 import java.util.List;
 5 
 6 import com.demo.po.Dog;
 7 
 8 public class LambdaMain {
 9 
10     public static void main(String[] args) {
11         List<Dog> list = new ArrayList<Dog>();
12         list.add(new Dog("小黃", 5));
13         list.add(new Dog("小花", 4));
14         list.add(new Dog("旺財", 3));
15         list.add(new Dog("團團", 2));
16         list.add(new Dog("圓圓", 1));
17 
18         // 排序
19         System.out.println("lambda集合排序!!!");
20         // sort的引數是介面函式,需要使用lambda表示式匿名函式形式
21         list.sort((dog1, dog2) -> dog1.getAge() - dog2.getAge());
22         System.out.println(list);
23         System.out.println();
24 
25         // 遍歷集合
26         System.out.println("lamdba集合遍歷:");
27         list.forEach(System.out::println);
28     }
29 
30 }

9、@FunctionalInterface註解,此註解是函式式介面註解,所謂的函式式介面,當然首先是一個介面,然後就是在這個接口裡面只能有一個抽象方法。這種型別的介面也稱為SAM介面,即Single Abstract Method interfaces。

特點:

  1)、介面有且僅有一個抽象方法。
  2)、執行定義靜態方法。
  3)、允許定義預設方法。
  4)、允許java.lang.Object中的public方法。
  5)、該註解不是必須的,如果一個介面符合"函式式介面"定義,那麼加不加該註解都沒有影響。加上該註解能夠更好的讓編譯器進行檢查。如果編寫的不是函式時介面,但是加上該註解,那麼編譯器會報錯。

 1 package com.demo.main;
 2 
 3 public class LambdaMain {
 4 
 5     public static void main(String[] args) {
 6         FunctionInterface functionInterface = (int a) -> {
 7             System.out.println("a = " + a);
 8         };
 9         functionInterface.add(10);
10     }
11 
12     /**
13      * 正確的函式式介面
14      * 
15      * @author biexiansheng
16      *
17      */
18     @FunctionalInterface
19     interface FunctionInterface {
20 
21         /**
22          * 抽象方法
23          */
24         public void add(int a);
25 
26         /**
27          * java.lang.Object中的public方法
28          * 
29          * @param var
30          * @return
31          */
32         public boolean equals(Object var);
33 
34         // 預設的方法
35         public default void defaultMethod() {
36             System.out.println("預設的方法!!!");
37         }
38 
39         // 靜態方法
40         public static void staticMethod() {
41             System.out.println("靜態的方法!!!");
42         }
43 
44     }
45 
46 }

10、系統內建函式式介面,Java8的推出,是以lamdba重要特性,一起推出的,其中系統內建了一系列函式式介面。在jdk的java.util.function包下,有一系列的內建函式式介面:

 1 package com.demo.main;
 2 
 3 import java.util.function.IntConsumer;
 4 import java.util.function.IntFunction;
 5 import java.util.function.IntPredicate;
 6 
 7 public class LambdaMain {
 8 
 9     public static void main(String[] args) {
10         // 在jdk的java.util.function包下,有一系列的內建函式式介面
11         // 1、使用int函式介面
12         IntFunction<Integer> intFunction = (a) -> {
13             return a + 10;
14         };
15         System.out.println(intFunction.apply(20));
16         
17         // 2、使用int判斷函式介面
18         final int aa = 20;
19         IntPredicate intPredicate = (a) -> {
20             return a == aa;
21         };
22         System.out.println(intPredicate.test(aa));
23         
24         // 3、使用int傳遞引數的形式
25         IntConsumer intConsumer = (a) -> {
26             System.out.println("a = " + a);
27         };
28         intConsumer.accept(20);
29         
30         // 書寫技巧:首先定義一個介面函式物件,然後後面跟lambda表示式。
31         // lambda引數列表根據介面函式的方法引數型別和引數個數。
32         // lambda的方法體,是否有返回值,根據介面函式的方法是否有返回值。
33     }
34 
35 }