“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
處理。