lambda表達式是Java8中最重要的特性之一更舞,也是Stream,Optional等特性的基礎。盡管lambda表達式與匿名內部類在JVM層面有本質不同坎吻,但我個人還是傾向于將lambda看做匿名內部類的語法糖八秃,主要用途就是簡化代碼和增加代碼的可讀性。在學習lambda表達式之前姐仅,先要回顧一下Java中的匿名內部類仗颈。
匿名內部類
匿名內部類即沒有名字的內部類,如我們在臨時創(chuàng)建新的線程時,經常會這么寫
new Thread(new Runnable(){
@Override
public void run(){
// do something
}
})
本來應該傳給new Thread()構造函數(shù)一個實現(xiàn)了Runnable接口的類诸尽,但是如果這個類只用到一次原杂,那么還要給他命名豈不是很麻煩,所以就省略了名字您机,即用匿名內部類來代替穿肄。但我們可以發(fā)現(xiàn),即使省略了類名际看,上面的代碼看上去還是廢話很多咸产,因為其實我們只關心run方法里面的內容,其他都是沒用的廢話仲闽。
lambda表達式
lambda表達式即匿名表達式脑溢,也被稱為閉包。lambda語法如下
(parameters) -> expression 或者(parameters) -> {statement}
- 可選參數(shù)類型聲明蔼囊,參數(shù)類型可自動推導
- 可選的參數(shù)圓括號焚志,只有一個參數(shù)衣迷,可以省略圓括號
- 可選的大括號 ,表達式只有一句話可以省略大括號
- 可選的返回關鍵字酱酬,主體只有一個表達式壶谒,可以省略顯示return關鍵字,編譯器會自動返回
// 舉例如下
() -> System.out.println(x);
str -> System.out.println(str);
(int x, int y) -> x+y;
(int x, int y) -> {
int temp1 = x+y;
int temp2 = x-y;
return temp1*temp2;
}
有了lambda表達式之后膳沽,我們可以大大簡化上面創(chuàng)建線程的代碼
new Thread(() -> doSomething())
函數(shù)式接口
lambda表達式能夠良好工作還離不開一個函數(shù)式接口汗菜。函數(shù)式接口是指有且僅有一個抽象方法的接口,如上面的Runnable只具有一個抽象方法void run(){},就是一個函數(shù)式接口挑社,所以函數(shù)式接口本質上和普通接口沒有什么區(qū)別陨界。
函數(shù)式接口可以使用@FunctionalInterface注解標識,被該注解標注的接口具有多個非抽象方法時痛阻,則會編譯報錯菌瘪。
lambda表達式可以直接賦值給對應函數(shù)式接口聲明的引用,如
Runnable runnable = () -> System.out.println("I am running");
runnable.run() // 輸出 I am running
new Thread(runnable).start(); // 輸出 I am running
因此阱当,我們可以直接將lambda表達式傳遞給以函數(shù)式接口作為參數(shù)的方法俏扩。以List的forEach方法為例
// List接口中的forEach定義如下,其中accept方法為Consumer接口中聲明的唯一抽象方法
default void forEach(Consumer<? super T> action){
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
List<String> lists = Arrays.asList("a","b","c");
lists.forEach(str -> System.out.println(str.toUpperCase())); //打印輸出A B C
// 如果將上一句代碼改為匿名內部類的寫法
lists.forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.print(s.toUpperCase());
}
});
除了上面代碼中提到的Consumer接口,java8中還為我們提供了非常多的函數(shù)式接口弊添,如Predicate<T>接口录淡,接受一個參數(shù),返回一個boolean值油坝。具體用到嫉戚,可再做了解。