java1.8 lambda表示式 函數語言程式設計 閉包
java1.8出來好久一直沒怎麼關注。這段時間公司的專案資料處理,需要頻繁操作集合,用for遍歷集合做計算,感覺很費勁,而且有大量重複程式碼。可讀性也不高。這時候想到java1.8新特性之一:函數語言程式設計
一、函式式介面 (functional interface)
@FunctionalInterface 可以不用加該註解,編譯的時候,對於只有一個抽象方法的介面,預設就是函式式介面。@FunctionalInterface interface DoSomeThing { int getAge(int a, int b); static void getName() { System.out.println("函式式介面的靜態方法"); } default void getAge() { System.out.println("函式式介面的預設方法"); } }
如果一個方法接受一個函式式介面作為引數,那麼我們可以傳入以下型別作為引數:
- 匿名內部類(Anonymous Inner Class)(Java的以前版本中經常使用的方式,在Java 8中不再被推薦)
- Lambda表示式
- 方法或者構造器的引用(Method or Constructor Reference
二、閉包(closure)(回顧)
lambda表示式大量用到了閉包和函式回撥,java1.8之前不支援顯性閉包,要實現程式碼片段的傳遞,只能通過內部類的方式,模擬閉包。
閉包簡而言之就是 含有狀態的函式。
在java語言中,閉包的應用:一個程式碼段被用來做為方法的引數.
java中沒有直接使用某個方法做為另一個方法的引數的,java使用匿名內部類來模擬這種情況。
比如一個二元函式 f _x,y,x,y是函式內部使用的變數,在只給定 一個引數 x = 7 的情況下, x 已經繫結,但是y還是自由的,這個時候 f(7, y) 就相當於含有一個私有變數(x=7)的函數了。當再給定另外一個變數 y 的值就可對函式完整的求值。所以函式中 有的引數是繫結的,有的引數自由的,這樣的機制稱為閉包。
閉包的價值在於可以作為函式物件或者匿名函式,持有上下文資料,作為第一級物件進行傳遞和儲存。閉包中的部分變數沒有在引用者的作用域內宣告,對於引用者這些變數就是自由變數。
由於閉包上下文中有引用指向了內部類的宿主,所以宿主物件在沒有其他引用的情況下也不會被銷燬,只有該閉包中的回撥函式執行完,才會被GC回收。
[注:在A作用域中使用的變數x(A一般為主執行緒的方法,主動呼叫者),卻沒有在A作用域中宣告(即在其他作用域中宣告的),對於A作用域來說,x就是一個自由變數],比如fun(x,y){},x和y是函式自己定義的,就不是自由變數,如果x是使用其他函式定義的,就是自由變數
總結:瞭解完閉包之後,我們知道在java1.8中不需要用內部類的方式實現閉包。
Lambda表示式會被編譯器轉換成相應函式式介面的一個例項,它表示式提供了一個上下文環境,既能引用該例項作用域的變數,又可以引用主程式所在作用域的所有變數。這種效果就是閉包,該例項中的變數就是自由變數。
閉包就是一個函式引用另外一個函式的變數,因為變數被引用著所以不會被回收,因此可以用來封裝一個私有變數。這是優點也是缺點,不必要的閉包只會徒增記憶體消耗
http://blog.csdn.net/hnust_xiehonghao/article/details/46326997
根據groovy中的閉包來理解
一個groovy閉包就像一個程式碼塊或者方法指標,他是定義然後執行的一段程式碼,但是他有一些特性:隱含變數,支援自由變數,支援currying 。
我們先來看看一些例子:
1 |
def clos
= { println "hello!" } |
2 |
3 |
println "Executing
the Closure:" |
4 |
clos() //prints
"hello!" |
在上面的例子中”hello!”是因為呼叫clos()函式才打印出來的,而不是在定義的時候打印出來的。
引數
閉包的引數在->之前列出,比如:
1 |
def printSum
= { a, b -> print a+b
} |
2 |
printSum( 5 , 7 ) //prints
"12" |
如果閉包的引數是少於2個的話,那麼 ->是可以省略的。
Parameter notes
A Closure without -> , i.e. {} , is a Closure with one argument that is implicitly named as ‘it’. (see below for details) In some cases, you need to construct a Closure with zero arguments, e.g. using GString for templating, defining EMC Property etc. You have to explicity define your Closure as { -> } instead of just { }
You can also use varargs as parameters, refer to the Formal Guide for details. A JavaScript-style dynamic args could be simulated, refer to the Informal Guide.
自由變數
閉包能引用在引數列表中沒有列出的變數,這些變數成為自由變數,他們的作用範圍在他們定義的範圍內:
1 |
def myConst
= 5 |
2 |
def incByConst
= { num -> num + myConst } |
3 |
println incByConst( 10 ) //
=> 15 |
另外一個例子:
1 |
def localMethod()
{ |
2 |
def localVariable
= new java.util.Date() |
3 |
return { println localVariable
} |
4 |
} |
5 |
6 |
def clos
= localMethod() |
7 |
8 |
println "Executing
the Closure:" |
9 |
clos() //prints
the date when "localVariable" was defined |
隱式變數
it
如果你有一個閉包但是隻有一個引數,那麼你可以省略這個引數,比如:
1 |
def clos
= { print it
} |
2 |
clos( "hi
there" )
|