1. lambada表達式簡介
Lambda 表達式是一種匿名函數(對 Java 而言這並不完全正確,但現在姑且這麼認爲),簡單地說,它是沒有聲明的方法,也即沒有訪問修飾符、返回值聲明和名字。
你可以將其想做一種速記,在你需要使用某個方法的地方寫上它。當某個方法只使用一次,而且定義很簡短,使用這種速記替代之尤其有效,這樣,你就不必在類中費力寫聲明與方法了。
Java 中的 Lambda 表達式通常使用 (argument) -> (body) 語法書寫,例如:
(arg1, arg2...) -> { body }
(type1 arg1, type2 arg2...) -> { body }
常見的寫法如下
(int a, int b) -> { return a + b; }
() -> System.out.println("Hello World");
(String s) -> { System.out.println(s); }
() -> 42
() -> { return 3.1415 };
2. Lambda 表達式的結構
- 一個 Lambda 表達式可以有零個或多個參數
- 參數的類型既可以明確聲明,也可以根據上下文來推斷。例如:(int a)與(a)效果相同
- 所有參數需包含在圓括號內,參數之間用逗號相隔。例如:(a, b) 或 (int a, int b) 或 (String a, int b, float c)
- 空圓括號代表參數集爲空。例如:() -> 42
- 當只有一個參數,且其類型可推導時,圓括號()可省略。例如:a -> return a*a
- Lambda 表達式的主體可包含零條或多條語句
- 如果 Lambda 表達式的主體只有一條語句,花括號{}可省略。匿名函數的返回類型與該主體表達式一致
- 如果 Lambda 表達式的主體包含一條以上語句,則表達式必須包含在花括號{}中(形成代碼塊)。匿名函數的返回類型與代碼塊的返回類型一致,若沒有返回則爲空
3. 函數式接口
函數式接口是隻包含一個抽象方法聲明的接口.java.lang.Runnable 就是一種函數式接口,在 Runnable 接口中只聲明瞭一個方法 void run(),相似地,ActionListener 接口也是一種函數式接口,我們使用匿名內部類來實例化函數式接口的對象,有了 Lambda 表達式,這一方式可以得到簡化。
每個 Lambda 表達式都能隱式地賦值給函數式接口,例如,我們可以通過 Lambda 表達式創建 Runnable 接口的引用。
Runnable r = () -> System.out.println("hello world");
編譯器會把lambada表達式當做一個函數來編譯.
4. 常見的函數式接口
4.1 Runnable
Runnable runnable = ()->{
System.out.println(Thread.currentThread().getName());
};
Thread thread = new Thread(runnable);
thread.start();
- Runnable只有一個run函數,且run函數沒有參數
4.2 Consumer接口
Consumer接口接收一個參數,不返回參數
public static void consumerFun(int value, Consumer<Integer> c) {
c.accept(value);
}
//調用
consumerFun(1,(value)->{
System.out.println(value);
});
4.3 BinConsumer接口
與Consumer接口一樣,只不過接收兩個參數,返回0個參數
public static void binConsumerFun(String a, String b, BiConsumer<String, String> binc) {
binc.accept(a, b);
}
//調用
binConsumerFun("hello", "maskwang", (a,b)->{
System.out.println(a+b)
});
4.4 Predication
作用接收一個參數,返回一個boolean值
public static boolean predicateFun(int value, Predicate<Integer> pre) {
return pre.test(value);
}
//調用
System.out.println(predicateFun(3, x->x==3));
4.5 Supplier
作用是接收0個參數,返回一個值
public static int supplierFun(Supplier<Integer> supplier) {
return supplier.get();
}
//調用
System.out.println(supplierFun(()->1));
4.5 Comparator
lambada表達式實現Comparator
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(3);
list.add(2);
list.sort((a,b) -> {return a>b?-1:1;});
//另一種方式
list.forEach(System.out::println)
4.6 集合的操作
實現集合的遍歷
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(3);
list.add(2);
list.forEach((value)->System.out.println(value));
5. Lambda表達式與匿名內部類的聯繫和區別
聯繫:
- lambda表達式創建的對象與匿名內部類生成的對象一樣,可以直接調用接口中繼承的默認方法。
區別:
-
匿名內部類可以爲任意接口創建實例,不管接口中包含多少個抽象方法,只要在匿名內部類中實現所有抽象方法即可。 但在lambda表達式中只能爲函數式接口創建實例。
-
匿名內部類可以爲抽象類甚至普通類創建實例;但lambda表達式只能爲函數式接口創建實例。
-
匿名內部類實現的抽象方法可以允許調用接口中定義默認方法。但lambda表達式的代碼塊不允許調用接口中定義默認方法。
6. 總結
Lambda 表達式賦予了 Java 相較於其他函數式編程語言缺失的特性,結合虛擬擴展方法之類的特性,Lambda 表達式能寫出一些極好的代碼。希望能在以後寫代碼的過程中,把這些用上去,使整個代碼看起來很簡潔.
ps: ::運算符是方法的引用,用這種方式可以簡單代替Lambada
String::valueOf x -> String.valueOf(x)
Object::toString x -> x.toString()
x::toString () -> x.toString()
ArrayList::new () -> new ArrayList<>()