百家爭鳴 Java需要引入閉包嗎?
首先先了解一下什么是閉包
閉包是可以包含自由(未綁定)變量 的代碼塊;這些變量不是在這個代碼塊或者任何全局上下文中定義的,而是在定義代碼塊的環境中定義。“閉包” 一詞來源于以下兩者的結合:要執行的代碼塊(由于自由變量的存在,相關變量引用沒有釋放)和為自由變量提供綁定的計算環境(作用域)。
可能上面的定義有點晦澀,下面看一下《Python 核心編程》對閉包的解釋。
如果在一個內部函數里,對在外部作用域(但不是在全局作用域)的變量進行引用,那么內部函數就被定義為閉包 。定義在外部函數內的但由內部函數引用或者使用的變量被稱為自由變量 。
下面是一個閉包的例子 (由于Java現在不支持閉包,這個閉包的例子是用Python寫的,參見了《Python 核心編程》 )
Python代碼
- def counter(start_at = 0):
- count = [start_at]
- def incr():
- count[0] += 1
- return count[0]
- return incr
- def counter(start_at = 0):
- count = [start_at]
- def incr():
- count[0] += 1
- return count[0]
- return incr
這里面count變量 就是一個 相對于函數incr 的自由變量(它在 函數incr 的外部作用域上,但又不在全局作用域上),內部函數incr 可以引用和使用這個變量。這個例子主要模擬一個計數器。
運行下面的代碼
Java代碼
- count = counter(6)
- print count()
- print count()
- count = counter(6)
- print count()
- print count()
就會打印出
7
8
我們發現 內部函數(incr)不但可以引用其自身定義的變量,還可以引用外部函數(counter)定義的變量。或者說 內部函數(閉包) 可以記憶狀態, 它可以根據 它記憶的狀態 來執行不同的操作。 而外部函數負責初始化狀態(內部函數需要記憶的狀態)。
那么為什么需要閉包,閉包的優勢是什么呢?我覺得就是可以記憶狀態,但對象也可以記憶狀態(通過對象的屬性)。那閉包和對象的區別是什么呢? 我覺得就因為閉包是函數而不是對象。我們會發現,如果用面向對象的方式來表達閉包內部函數(閉包)就像 對象的方法而外部函數 對象的構造器。構造器用來初始化對象狀態而對象的方法可以根據 對象的狀態 來執行不同的操作。
好!下面我們用面向對象的方式 創建一個 計數器(實現和上例一樣的功能,用Java實現)。
Java代碼
- public class Counter {
- private int startAt;
- public Counter() {
- this(0);
- }
- public Counter(int startAt) {
- this.startAt = startAt;
- }
- public int incr(){
- return ++ this.startAt;
- }
- }
- public class Counter {
- private int startAt;
- public Counter() {
- this(0);
- }
- public Counter(int startAt) {
- this.startAt = startAt;
- }
- public int incr(){
- return ++ this.startAt;
- }
- }
運行Test類
Java代碼
- public class Test{
- public static void main(String[] args){
- Counter counter = new Counter(6);
- System.out.println(counter.incr());
- System.out.println(counter.incr());
- }
- }
- public class Test{
- public static void main(String[] args){
- Counter counter = new Counter(6);
- System.out.println(counter.incr());
- System.out.println(counter.incr());
- }
- }
會打印出(和上例打印輸出相同)
7
8
那么Java(有了對象)還需要引入閉包嗎?我覺得不需要,因為對象完全可以模擬閉包的行為,而且對象才是OOP 的一級元素。閉包是函數式編程(FP)中的概念,引入閉包就相當于引入FP,這只會破壞Java的純粹與簡單。
【編輯推薦】