百家爭鳴 Java需要引入閉包嗎?
首先先了解一下什么是閉包
閉包是可以包含自由(未綁定)變量 的代碼塊;這些變量不是在這個代碼塊或者任何全局上下文中定義的,而是在定義代碼塊的環(huán)境中定義?!伴]包” 一詞來源于以下兩者的結(jié)合:要執(zhí)行的代碼塊(由于自由變量的存在,相關(guān)變量引用沒有釋放)和為自由變量提供綁定的計算環(huán)境(作用域)。
可能上面的定義有點(diǎn)晦澀,下面看一下《Python 核心編程》對閉包的解釋。
如果在一個內(nèi)部函數(shù)里,對在外部作用域(但不是在全局作用域)的變量進(jìn)行引用,那么內(nèi)部函數(shù)就被定義為閉包 。定義在外部函數(shù)內(nèi)的但由內(nèi)部函數(shù)引用或者使用的變量被稱為自由變量 。
下面是一個閉包的例子 (由于Java現(xiàn)在不支持閉包,這個閉包的例子是用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變量 就是一個 相對于函數(shù)incr 的自由變量(它在 函數(shù)incr 的外部作用域上,但又不在全局作用域上),內(nèi)部函數(shù)incr 可以引用和使用這個變量。這個例子主要模擬一個計數(shù)器。
運(yùn)行下面的代碼
Java代碼
- count = counter(6)
- print count()
- print count()
- count = counter(6)
- print count()
- print count()
就會打印出
7
8
我們發(fā)現(xiàn) 內(nèi)部函數(shù)(incr)不但可以引用其自身定義的變量,還可以引用外部函數(shù)(counter)定義的變量?;蛘哒f 內(nèi)部函數(shù)(閉包) 可以記憶狀態(tài), 它可以根據(jù) 它記憶的狀態(tài) 來執(zhí)行不同的操作。 而外部函數(shù)負(fù)責(zé)初始化狀態(tài)(內(nèi)部函數(shù)需要記憶的狀態(tài))。
那么為什么需要閉包,閉包的優(yōu)勢是什么呢?我覺得就是可以記憶狀態(tài),但對象也可以記憶狀態(tài)(通過對象的屬性)。那閉包和對象的區(qū)別是什么呢? 我覺得就因為閉包是函數(shù)而不是對象。我們會發(fā)現(xiàn),如果用面向?qū)ο蟮姆绞絹肀磉_(dá)閉包內(nèi)部函數(shù)(閉包)就像 對象的方法而外部函數(shù) 對象的構(gòu)造器。構(gòu)造器用來初始化對象狀態(tài)而對象的方法可以根據(jù) 對象的狀態(tài) 來執(zhí)行不同的操作。
好!下面我們用面向?qū)ο蟮姆绞?創(chuàng)建一個 計數(shù)器(實現(xiàn)和上例一樣的功能,用Java實現(xiàn))。
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;
- }
- }
運(yùn)行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 的一級元素。閉包是函數(shù)式編程(FP)中的概念,引入閉包就相當(dāng)于引入FP,這只會破壞Java的純粹與簡單。
【編輯推薦】