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 }