背景
在Java編碼中秉颗,經(jīng)常性的會使用到匿名類,有些時候澜建,這些匿名類非常簡單向挖,里面僅包含一個方法,類如Runnable
接口炕舵,這種匿名類寫起來會非常的難看何之。其實我們僅僅想把這個唯一的一個方法當(dāng)做參數(shù)傳遞,在JDK8中咽筋,Lambda表達(dá)式這個特性就能滿足你的這個需求溶推。
From
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("hello lambda!");
}
});
To
new Thread(() -> System.out.println("hello lambda!"));
語法
一個Lambda表達(dá)式包含如下三個部分
參數(shù)列表 | 箭頭符號 | 函數(shù)體 |
---|---|---|
(int x, int y) | -> | x + y |
函數(shù)體可以是一行表達(dá)式,也可以是一段代碼塊奸攻。幾個例子如下:
(int x, int y) -> x + y
() -> 42
(String s) -> { System.out.println(s); }
第一個參數(shù)為x和y蒜危,返回x+y的結(jié)果
第二個無參,直接返回42
第三個接收一個String類型睹耐,并打印出來
一般僅包含一個方法的匿名類舰褪,均可以使用lambda表達(dá)式的方法書寫。
java.util.function包
這里為什么提到這個包呢疏橄,因為lambda表達(dá)式要求占拍,匿名類中僅有一個未實現(xiàn)的方法略就,這樣才能寫成上述的形式,在java.util.function包中晃酒,有一些大家較為熟悉的接口表牢,如
- Predicate: 測試一個傳入的參數(shù)是否符合要求
- Consumer: 消費傳入的參數(shù),對傳入的參數(shù)進行對應(yīng)的處理
- Function: 對傳入的T類型參數(shù)轉(zhuǎn)換成R類型的返回
- Supplier: 生成一個T類型的對象贝次,類似Factory方法
示例
-
Predicate
可以直接使用
Predicate<String> p =(s)->s.indexOf("a")>-1;
Predicate<String> p1=(s)->s.endsWith("b");
System.out.println(p.test("sda")); //直接使用p校驗
System.out.println(p.and(p1).test("asdb")); //p和p1兩個條件聯(lián)合校驗
或者結(jié)合類似filter
方法使用
Optional<String> optional=Optional.of("aaa");
System.out.println(optional.filter(s -> s.indexOf("b")>-1));
- Consumer
Consumer<String> c = s -> System.out.println(s + "aaa");
Consumer<String> c1 = s -> System.out.println(s + "bbb");
c.accept("as");
c.andThen(c1).accept("as");
或者結(jié)合類似Optional
中的ifPresent
使用
Optional<String> optional = Optional.of("aaa");
optional.ifPresent(s -> System.out.println(s));
- Function
Function<String,Integer> f=s -> Integer.parseInt(s);
System.out.println(f.apply("123"));
或者結(jié)合Optional
中的map
方法使用
Optional<String> optional = Optional.of("123");
optional.map(s -> Integer.parseInt(s));
- Supplier
Supplier<String> s= () -> "asd";
System.out.println(s);
Supplier<String> s= () -> "asd";
System.out.println(s);
實現(xiàn)
翻看源碼崔兴,會發(fā)現(xiàn)上述的接口,均使用了@FunctionalInterface
注解
@FunctionalInterface
public interface Consumer<T> {
查看其說明蛔翅,這個注解僅適用于接口敲茄,且要求接口中僅包含一個未實現(xiàn)的方法(默認(rèn)實現(xiàn)不算在內(nèi)),若我們的接口中包含1個以上的未實現(xiàn)的方法的時候山析,編譯的時候會提示錯誤
所以這個
java.util.function
包中的接口簡直就是給lambda表達(dá)式定制的堰燎。
后注
然而,在性能方面笋轨,大部分的時候秆剪,直接使用lambda表達(dá)式的表現(xiàn)并不比傳統(tǒng)的寫作方式好,例如下面兩塊代碼
for (int i = 0; i < 10000; i++) {
optional.filter((s) -> s.indexOf("b") > -1);
}
for (int i = 0; i < 10000; i++) {
optional.filter(new Predicate<String>() {
@Override
public boolean test(String s) {
return s.indexOf("b") > -1;
}
});
}
耗費的時間爵政,一個是43仅讽,一個是3,相差接近10倍钾挟,但是如果我將上面的代碼塊寫成如下
Predicate<String> p = (s) -> s.indexOf("b") > -1;
for (int i = 0; i < 10000; i++) {
optional.filter((s) -> s.indexOf("b") > -1);
}
兩種的時間消耗就差不多洁灵,所以就現(xiàn)在的編譯器(本地使用的1.8_111的版本)而言,在lambda上面的優(yōu)化顯然沒有傳統(tǒng)的匿名類做的好掺出,所以個人有如下幾點建議
- 在有大量循環(huán)的時候徽千,建議使用傳統(tǒng)方式
- 在無性能要求或者相差不大的情況下,當(dāng)然是lambda
- 當(dāng)使用到
Stream API
的時候蛛砰,優(yōu)先考慮使用parallelStream
并行流來處理 - 現(xiàn)在JDK的版本已經(jīng)發(fā)布到10,后面針對lambda的優(yōu)化一定會提上日程黍衙,所以還是建議大家可以現(xiàn)在開始嘗試使用泥畅,感受一下函數(shù)式變成的魅力
借鑒
- http://www.oracle.com/technetwork/java/jvmls2013kuksen-2014088.pdf
- https://www.beyondjava.net/performance-java-8-lambdas
感謝閱讀!