簡單定義 – Definition
用來實作 @FunctionalInterface
中 SAM(Single Abstract Method)
的匿名method 表示法
@FunctionalInterface
- 只能用來標示Interface.
- 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
- java.lang.Runnable
- java.util.Comparator
- 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中
- Predicate : boolean test(T t)回傳boolean做為可否的依據。
- Consumer : void accept(T t)直接處理,不用回傳結果。
- Function : R apply(T t),處理後要回傳結果。
- 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::println
與Integer::compareTo
就是用來簡化Lambda表示法。
雖說是簡化啦,但我個人不是很想看到這種寫法…
總結
因為要有@FunctionalInterface
才能看到Lambda,所以也不是隨便就看得到。
而實際開發上,除了Runable與Collection外,不是很常看到Lambda,所以專注在這兩類上的應用上就好。
Lambda不難懂也易用,但過度的簡化對團隊來說不一定是好事。