本文已授權"後端技術精選"獨家釋出。
“Lambda 表示式”(lambda expression)是一個匿名函式,Lambda表示式基於數學中的λ演算得名,直接對應於其中的lambda抽象(lambda abstraction),是一個匿名函式,即沒有函式名的函式。Lambda表示式可以表示閉包(注意和數學傳統意義上的不同)。
認識lambda
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("匿名內部類的執行");
}
}).start();
}
複製程式碼
設計匿名內部類的目的,就是為了方便程式猿將程式碼作為資料來傳遞。但是你會發現,這個物件看起來是很多餘的,所以我們不想傳入物件,只想傳入行為。
new Thread(()->{
System.out.println("lambda代替內部類");
}).start();
複製程式碼
和實現某介面的物件不同,我們傳入了一段程式碼塊--一個沒有名字的函式。->
將引數和表示式主體分開,左邊是引數,右邊是方法體。
Lambda的不同形式
Runnable runnable = ()-> System.out.println("hello world");
複製程式碼
該Lambda表示式不包含引數(因為是空括號)。
interface Test{
void oneParam(String name);
}
Test test = s -> System.out.println("oneParam方法傳遞引數:"+s);
test.oneParam("我是傳遞的值");
控制檯輸出:
oneParam方法傳遞引數:我是傳遞的值
複製程式碼
(lambda只能用於函式式介面),如果引數只包含一個引數,可以省略引數的括號。
interface Test2{
int add(int a,int b);
}
Test2 test2 = (x,y) -> x+y;
int add = test2.add(10, 10);
System.out.println(add);
控制檯輸出:
20
複製程式碼
可以看到,我們在使用lambda的時候建立了一個函式x+y
,Test2
物件不是表示兩個數字的和,而是表示兩個數字相加的程式碼。以上的程式碼中,引數型別都是由編譯器自己推斷的,同樣,我們可以明確的宣告引數型別:
interface Test3{
long add(long a,long b);
}
Test3 test3 = (long x,long y) -> x+y;
long add = test3.add(10, 10);
複製程式碼
引用值的要求
Error:(25, 64) java: 從lambda 表示式引用的本地變數必須是最終變數或實際上的最終變數
String name = "FantJ";
Runnable runnable = ()-> System.out.println("hello " +name);
runnable.run();
複製程式碼
hello FantJ
複製程式碼
上面這段程式碼,Lambda可以引用非final變數這個屬性你可以早已瞭解,但是你更需要知道,java8只是放鬆了這一語法的限制,但實際上要求該變數還是final。
可以看到,不管name
在使用lambda
的前還是後做改動,lambda
都會報錯:表示式引用的本地變數必須是最終變數或實際上的最終變數,簡單的,我們可以稱他為既成事實上的final變數。所以,lambda也被稱為閉包。
Lambda表示式型別
java中,所有方法都有返回型別,那lambda返回型別是什麼呢。
是介面方法的返回型別。這一點前文有體現過。這裡再詳細解釋下。
interface Test{
void oneParam(String name);
}
複製程式碼
拿這個例子來講,oneParam
方法表示一種行為:接受一個String
,返回void
。只要方法名和行為和Lambda表示式匹配即可完成呼叫。
注意:如果編譯器猜不出引數和返回值的型別,則都將視為Object
處理。