Lambda表達式
Java的Lambda表達式形式為:
(params) -> { statements };
其中:
- 若params隻有1個,可以省略():
param -> { statements };
- 若params為0個,用()表示無參數:
() -> { statements };
- 若代碼為一行,則可省略{},無論該行代碼是否為表達式:
或(params) -> expression;
(params) -> statement;
函數式接口
Lambda表達式本質上是一個對象。而對象就必然有其對應的類型,就像一個字元串其類型為String一樣。
當一個函數,其參數需要傳入一個Lambda表達式時,函數的參數就需要明确定義該Lambda表達式的類型。
實際上,Java的Lambda表達式都是歸屬于某個具體已定義的類型的。根據Lambda表達式的參數與傳回值數量和類型,Java定義了一組interface來接收Lambda表達式,稱之為函數式接口。
函數式接口有以下條件:
- 是一個interface。
- 有且僅有一個抽象方法。
另外:
- interface預設繼承Java.lang.Object,故Object的抽象方法不包含在内。
- 可以使用@FunctionalInterface注解來标記函數式接口,有助于編譯器進行檢查。但@FunctionalInterface注解并非必須,隻要滿足條件,即使沒有@FunctionalInterface注解編譯器也會将接口識别為函數式接口。
例如:
@FunctionalInterface
public interface Runnable {
public abstract void run();
}
Java8以後,Runnable接口多了@FunctionalInterface注解。這表示Runnable接口成為函數式接口了,可以接收Lambda表達式。
而實際上,由于Runnable接口有且僅有一個抽象方法,滿足函數式接口的條件,是以即使不加@FunctionalInterface注解也依然會被識别為函數式接口。
是以可以自定義函數式接口:
@FunctionalInterface
public interface MyInterface {
// 定義唯一的抽象方法
void doWork();
// toString()屬于Object,不包含
String toString();
}
使用:
MyInterface myInterface = () -> System.out.println("do work");
或将其作為參數類型:
class MyClass {
public void doMyWork(MyInterface myInterface) {
myInterface.doWork();
}
}
MyClass myClass = new MyClass();
myClass.doMyWork(() -> System.out.println("do work"));
前面提到的Runnable接口同理。
除了Runnable接口,Java8還提供了一組函數式接口:
接口 | 參數 | 傳回類型 | 描述 |
---|---|---|---|
Predicate | T | boolean | 判斷一個對象是否符合條件。常用于對象過濾。 |
Function<T, R> | T | R | 将一個對象轉換為另一個對象。 |
Supplier | None | T | 提供一個對象。生産者-消費者中的生産者。 |
Consumer | T | void | 消費一個對象。生産者-消費者中的消費者。無傳回值。 |
UnaryOperator | T | T | 接收對象并傳回同類型的對象。 |
BinaryOperator | (T, T) | T | 接收兩個對象,并傳回一個原對象。這三個對象的類型都相同。 |
其中:
- Supplier是唯一無參數的函數。其他函數都必須傳入參數。
- Consumer是唯一無傳回的函數。其他函數都會傳回一個對象。
Runnable接口則是無參數,無傳回值的。