Java Lambda

簡單定義 – Definition

用來實作 @FunctionalInterfaceSAM(Single Abstract Method)的匿名method 表示法

@FunctionalInterface

  1. 只能用來標示Interface.
  2. Interface裡面只能有一個非繼承而的來,且未實做的method。

第二點要解釋一下,看一下java.util.Comparator

@FunctionalInterface
public interface Comparator<T> {
    int compare(T o1, T o2);

    boolean equals(Object obj);

    default Comparator<T> reversed() {
        return Collections.reverseOrder(this);
   }

   ....
}

其中equals是從java.lang.Object來的,所以不算,reversed則是用了keyword default有了實做不算,所以只有compare算是lambda要實做的method.

Lambda 表示法 – Expression

(arguments ...) -> {
    statements ...

    return result;
}

雖然在僅有一個argument或statements僅有一行時,()或{}是可以省略的,但我個人比較喜歡不省略。

常見的舊有 FunctionalInterface

  1. java.lang.Runnable
  2. java.util.Comparator
  3. java.io.FileFilter

簡單實例

/* Runnable 定義*/
@FunctionalInterface
public interface Runnable {
    public abstract void run();
}

/* 用lambda實作*/
Runnable x = () -> { System.out.println("run"); };
x.run();

JDK8 後加入的 FunctionalInterface

都在java.util.function中

  1. Predicate : boolean test(T t)回傳boolean做為可否的依據。
  2. Consumer : void accept(T t)直接處理,不用回傳結果。
  3. Function : R apply(T t),處理後要回傳結果。
  4. Supplier : T get(),不用給參數,直接取回要的結果。

簡單實例


List<String> vlist = new ArrayList<>(); vlist.add("123"); vlist.add("23"); vlist.add("5"); vlist.add("23456"); Predicate<String> moreThanThree = (v) -> {return v.length() > 3;}; Consumer<String> systemPrint = (v) -> {System.out.println(v);}; Stream<String> stream = vlist.stream().filter(moreThanThree); stream.forEach(systemPrint); //極簡化 vlist.stream().filter(v -> v.length() > 3).forEach(v -> System.out.println(v));
/*利用Comparator取得最小值*/
List<Integer> iList = new ArrayList<>();
iList.add(2);
iList.add(1);
iList.add(3);

Integer min = iList.stream().min((i1, i2) -> {return i1.compareTo(i2);}).get();

:: Method reference

JDK 8 加入了一個特別的Operator - ::,專用在Lambda裡,讓程式碼再簡化。
當Lambda使用其他Class裡的Method,而該Method使用的參數與回傳值與Lambda要表示的一致時,可以直接使用::來引用。

以先前使用的例子來看

Consumer<String> systemPrint1 = (v) -> {System.out.println(v);};
Consumer<String> systemPrint2 = System.out::println;
Integer min1 = iList.stream().min((i1, i2) -> {return i1.compareTo(i2);}).get();
Integer min2 = iList.stream().min(Integer::compareTo).get();

其中System.out::printlnInteger::compareTo就是用來簡化Lambda表示法。

雖說是簡化啦,但我個人不是很想看到這種寫法…

總結

因為要有@FunctionalInterface才能看到Lambda,所以也不是隨便就看得到。
而實際開發上,除了Runable與Collection外,不是很常看到Lambda,所以專注在這兩類上的應用上就好。
Lambda不難懂也易用,但過度的簡化對團隊來說不一定是好事。

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *

這個網站採用 Akismet 服務減少垃圾留言。進一步了解 Akismet 如何處理網站訪客的留言資料