Java8學習筆記之Lambda表示式
使用Lambda表示式,我們可以很簡潔地傳遞程式碼(通常是匿名函式)。
結構
Lambda表示式主要分為三部分:引數列表,箭頭,Lambda 主體
語法
- (parameters) -> expression
- (parameters) -> { statements; }
如果表示式只有一行,用第一種,多行用第二種。
Java8中,標註了@FunctionalInterface
,表明這個介面將是一個函式式介面,它裡面只能有一個抽象方法。
常用的函式式介面
JDK已經為我們提供了很多常用的函式式介面:
* Predicate:java.util.function.Predicate<T>
* Consumer:
java.util.function.Consumer<T>
定義了一個名叫accept的抽象方法,它接受泛型T的物件,沒有返回(void)。如果需要訪問型別T的物件,並對其執行某些操作,就可以使用這個介面。 * Supplier:
java.util.function.Supplier<T>
不接受物件,返回一個泛型物件T。在需要new一個物件例項時可以使用。 * Function:
java.util.function.Function<T, R>
原始型別特化
我們知道,泛型只能繫結到引用型別的物件。因此,在使用泛型繫結基本型別的時候,Java會為我們自動裝箱和拆箱,但這是會消耗效能的。
如果輸入和輸出都是基本型別時,Java8為我們提供了新的函式式介面,以避免自動裝箱拆箱。
簡單列舉一部分:
* Predicate:IntPredicate
, LongPredicate
, DoublePredicate
* Consumer:IntConsumer
,LongConsumer
DoubleConsumer
* Supplier:
BooleanSupplier
, IntSupplier
, LongSupplier
, DoubleSupplier
* Function:
IntFunction<R>
,LongToDoubleFunction
,ToLongFunction<T>
從命名可以輕易看出從什麼型別轉成什麼型別,可以在java.util.function
包下檢視所有介面。
使用區域性變數
在使用lambda時,主體程式碼塊內允許使用的外部變數。但是,不允許改變外部變數。這些變數應該宣告為final
或者事實上是final
的(即之後程式碼中不會改變)
方法引用
方法引用主要有三類:
- 指向靜態方法的方法引用
- Lambda:
(args) -> ClassName.staticMethod(args)
- 方法引用:
ClassName :: staticMethod
- Lambda:
- 指向任意型別例項方法的方法引用
- Lambda:
(arg0, rest) -> arg0.instanceMethod(rest)
- 方法引用:
ClassName :: instanceMethod
(arg0 是 ClassName 型別的)
- Lambda:
- 指向現有物件的例項方法的方法引用
- Lambda:
(args) -> expr.instanceMethod(args)
- 方法引用:
expr :: intanceMethod
- Lambda:
除此之外,還有建構函式引用:ClassName :: new
比如用Map來將建構函式對映到字串值:
static Map<String, Function<Integer, Fruit>> map = new HashMap<>();
static {
map.put("apple", Apple::new);
map.put("orange", Orange::new);
// etc...
}
public static Fruit giveMeFruit(String fruit, Integer weight) {
return map.get(fruit.toLowerCase()).apply(weight);
}
複合 Lambda 表示式
Comparator、Predicate和Function等函式式介面都有幾個可以用來結Lambda表示式的預設方法。
比較器複合
- 普通排序
comparing()
Comparator<Apple> c = Comparator.comparing(Apple::getWeight);
- 逆序
reversed()
inventory.sort(comparing(Apple::getWeight).reversed());
- 比較器鏈
thenComparing()
inventory.sort(comparing(Apple::getWeight).reversed()
.thenComparing(Apple::getCountry));
謂詞複合
3個方法增強已有的Predicate介面:
* and
:與
* or
:或
* negate
:非
請注意,and和or方法是按照在表示式鏈中的位置,從左向右確定優先順序的。因此,a.or(b).and(c)可以看作(a || b) && c。
函式複合
Function介面有andThen
和compose
兩個預設方法,它們都會返回Function的一個例項。
舉個例子:
有2個函式,一個加1,一個乘2
Function<Integer, Integer> f = x -> x + 1; // f(x)=x+1
Function<Integer, Integer> g = x -> x * 2; // g(x)=2x
andThen()
Function<Integer, Integer> h = f.andThen(g); // g(f(x))
int result = h.apply(1); // 4
compose()
Function<Integer, Integer> h = f.compose(g); // f(g(x))
int result = h.apply(1); // 3