Java8學習筆記之Lambda表達式

Lambda.jpg

使用Lambda表達式,我們可以很簡潔地傳遞代碼(通常是匿名函數)。

結構

Lambda表達式主要分為三部分:參數列表,箭頭,Lambda 主體

語法

  • (parameters) -> expression
  • (parameters) -> { statements; }

如果表達式只有一行,用第一種,多行用第二種。

Java8中,標注了@FunctionalInterface,表明這個接口將是一個函數式接口,它里面只能有一個抽象方法。

常用的函數式接口

JDK已經為我們提供了很多常用的函數式接口:

  • Predicate:java.util.function.Predicate<T>接口定義了一個名叫test的抽象方法,它接受泛型T對象,并返回一個boolean。在需要表示一個涉及類型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>接口定義了一個叫作apply的方法,它接受一個泛型T的對象,并返回一個泛型R的對象。如果需要定義一個Lambda,將輸入對象的信息映射到輸出,就可以使用這個接口。

原始類型特化

我們知道,泛型只能綁定到引用類型的對象。因此,在使用泛型綁定基本類型的時候,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: (arg0, rest) -> arg0.instanceMethod(rest)
    • 方法引用:ClassName :: instanceMethod(arg0 是 ClassName 類型的)
  • 指向現有對象的實例方法的方法引用
    • Lambda: (args) -> expr.instanceMethod(args)
    • 方法引用:expr :: intanceMethod

除此之外,還有構造函數引用: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表達式的默認方法。

比較器復合

  1. 普通排序comparing()
Comparator<Apple> c = Comparator.comparing(Apple::getWeight);
  1. 逆序reversed()
inventory.sort(comparing(Apple::getWeight).reversed()); 
  1. 比較器鏈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接口有andThencompose兩個默認方法,它們都會返回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
  1. andThen()
Function<Integer, Integer> h = f.andThen(g); // g(f(x))
int result = h.apply(1); // 4
  1. compose()
Function<Integer, Integer> h = f.compose(g); // f(g(x))
int result = h.apply(1); // 3
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容