深入理解Java8Lambada表達式

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<>()
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章