java閉包
1. 閉包的語法結構
Groovy的閉包
閉包(Closure)是java所不具備的語法結構(JAVA8增加了對閉包的支持)。閉包就是一個代碼塊,用「{ }」包起來。此時,程序代碼也就成了數據,可以被一個變數所引用(與C語言的函數指針比較類似)。閉包的最典型的應用是實現回調函數(callback)。Groovy的API大量使用閉包,以實現對外開放。閉包的創建過程很簡單,例如:
{ 參數 ->
代碼...
}
參考下面的例子代碼,定義了c1和c2兩個閉包,並對它們進行調用:
def c1 = { println it }
def c2 = { text -> println text }
c1.call(content1) //用call方法調用閉包
c2(content2) //直接調用閉包
「->;」之前的部分為閉包的參數,如果有多個參數,之間可用逗號分割;「->;」之後的部分為閉包內的程序代碼。如果省略了「->;」和它之前的部分,此時閉包中代碼,可以用名為「it」的變數訪問參數。
閉包的返回值和函數的返回值定義方式是一樣的:如果有return語句,則返回值是return語句後面的內容;如果沒有return語句,則閉包內的最後一行代碼就是它的返回值。
2. java開發的缺點有哪些
我認為Java語言的10大問題是:
1、缺少閉包(closure):我想這個不需要解釋了。函數式編程已經存在幾十年了,但最近幾年,它們獲得了越來越多的關注,最主要的原因,是它可以自然地編寫並行程序。我部分的同意Joshua Bloch強調在Java中引入閉包的問題需要再想一想(BGGA提議的方式真的很糟),至少閉包的缺失,使得在Java中做任何真正的函數式編程都是不可能的。
2、缺少一等函數:這個問題與前一個有些關聯,但我認為它更糟糕。在Java里,要達到類似效果的唯一方式,是使用著名的、醜陋悲慘的單方法匿名內部類,但這看上去的確是一個拙劣的方法。甚至在C#中,也通過代理機制,提供了一個更好的實現。
3、原生類型(Primitive types):如果在Java中一切皆對象,那是多麼完美啊,但他們偏偏不這樣設計。因而,這一點導致了一些問題,比如,不能把一個int放到集合(Collection)里,這個在Java5中通過自動裝箱特性得到了解決(下面會提到)。它也造成了傳值與傳引用上的困擾,原生類型數據是通過值傳給方法的(復制一份拷貝,然後傳給函數),而真正的對象是通過傳遞(譯註:其實是復制對象地址再傳遞,因此應該也是傳值方式,只是由於函數內部可通過這個對象地址訪問對象,因此效果上類似傳引用)。
4、自動裝箱(Autoboxing)和自動拆箱(autounboxing):這個特性是為了解決因原生類型的存在所導致的問題,在Java5引入的。它允許靜默地轉換原生類型到相應的對象,但這常常導致其它的問題。比如Integer可以為null,但int不能,因此這時JVM只能拋出一個難以調試的空指針異常(NullPointerException)。此外,它還可能導致其它奇怪的行為,就像下面的例子,我們就很難理解,變數test為什麼是false:
Intger a = new Integer(1024);
Intger b = new Integer(1024);
boolean test = a < b || a == b || a > b;
5、缺少范型具類化:范型是Java5引入的一個很酷的特徵,但是為了保持與舊版本Java的兼容性,導致缺失某些重要的特性,尤其是不能在運行時反省范型的類型。例如,你有一個方法,接受List參數,如果傳進來一個List,你卻不能知道運行里該范型的確切類型。同理,你也不能創建范型數組。這意味著,盡管下面的代碼看起來很自然,但卻不編譯不了:
List[] listsOfStrings = new List[3];
6、不可避免的范型警告:你有發現過自己陷入不可能去掉的關於范型的警告么?如果你像我一樣大量使用范型,我打賭你碰到過。事實上,是這個問題的規模化症狀,讓他們認為需要引入一個特定的註解(@SuppressWarnings("unchecked"))來處理這種情況,我覺得,范型應該可能被設計的更好。
7、不能傳void給方法調用:我得承認,這種給方法傳遞void的需求,乍一看有些怪異。我喜歡DSL,當我實現自己的DSL庫(lambdaj)的一個特定特性時,我不得不需要一個方法聲明成這樣的簽名:void doSomething(Object parameter),這里為這個方法傳進來的參數parameter,是另一個方法調用的結果,它唯一的目的,是注冊調用(的對象)自身,以可以在以後執行它。讓我吃驚的是,即使println方法返回void,看上去也並沒有一個好理由,不允許我把代碼寫成這樣,:
doSomething(System.out.println("test"));
8、沒有原生的代理機制:代理是一種非常有效和應用廣泛的模式,但Java提供的代理機制,只針對介面,而不是具體類。這是為什麼象cblib這樣提供這種機制的庫,被如此多的主流框架,如Spring和Hibernate,採用的原因。此外,由於cglib通過運行時創建被代理類的子類來實現的,因此這些種方式有一個眾所周知的限制——不能代理final類,比如String。
9、差勁的Switch...case語句:Java規定,switch...case只能選擇int和enum(Java5開始)。這一點如果跟更現代的語言如Scala相比,看起來簡直太弱了。
10、受檢查異常(Checked exception):類似原生類型,受檢查異常也已經成為Java的一個罪孽之源。它迫使程序員必須做下面兩件極其糟糕討厭的事情中的一個:讓你的代碼里充斥大量的、糟糕難讀的、容易出錯的try...catch語句,而這樣做的最大意義,只是將捕獲的異常,包裝成運行時異常,然後再重新拋出;或者是讓大量的拋出聲明子句污染你的API,讓介面缺少靈活性和可擴展性。
真正的問題是,這里我提到的這幾大主要問題,唯一的解決辦法,是要做一個痛苦的決擇,定義一套新的語言規范,放下當前版本的向後兼容性。我猜他們永遠也不會這么做,雖然我相信,如果編寫一個能夠自動轉換舊Java源碼的程序,讓它們與假設的新版本兼容,並不是很困難。最後,這就是我決定開始尋找一個更好的JVM兼容語言的原因。
3. java8的特性有哪些
Lambda表達式(也稱為閉包)它允許我們將函數當成參數傳遞給某個方法,或者把代碼本身當作數據處理
Java 8使用兩個新概念擴展了介面的含義:默認方法和靜態方法。
方法引用使得開發者可以直接引用現存的方法、Java類的構造方法或者實例對象。方法引用和Lambda表達式配合使用,使得java類的構造方法看起來緊湊而簡潔,沒有很多復雜的模板代碼。
重復註解,Java 8中使用@Repeatable註解定義重復註解
Java 8編譯器在類型推斷方面有很大的提升,在很多場景下編譯器可以推導出某個參數的數據類型,從而使得代碼更為簡潔。
Java 8拓寬了註解的應用場景。
Java 8增加了很多新的工具類(date/time類),並擴展了現存的工具類,以支持現代的並發編程、函數式編程等。
4. 什麼是閉包
閉包是編程中一個關鍵概念,簡單來說,它是能夠在外部訪問並操作內部函數變數的函數。在JavaScript中,由於函數作用域的特性,只有內部函數能訪問局部變數,因此閉包可以理解為「定義在函數內部的函數」。實際上,閉包通過連接函數內部和外部環境,創建了一種持久的「數據包」,即使外部函數執行完畢,內部變數仍然有效,因為它們被閉包持有。
閉包的存在在多種編程語言中都有體現,包括PHP、Scala、Groovy、Java(從Java 8開始)、Python、Ruby等,它們支持不同程度的閉包功能。閉包的定義涉及集合的閉包性質,如集合的閉包定義為包含自身且滿足特定運算條件的子集,而閉包的特性如最小閉集、包含關系等,是其核心概念。
在實際應用中,閉包常用於模擬私有變數、實現回調函數、以及維護函數作用域內的狀態。例如,閉包可以用來創建計數器,或者在函數返回內部函數以保護變數不被外部訪問。同時,JavaScript的垃圾回收機制與閉包緊密相關,當一個函數返回一個內部函數時,外部函數的作用域會被保留,避免了資源的過早釋放。
理解閉包需要掌握函數執行環境、活動對象、作用域和作用域鏈的概念。在內存管理上,要謹慎使用閉包,避免內存消耗過大和可能的內存泄露問題。此外,正確處理閉包中變數的修改是關鍵,特別是在將閉包作為對象方法時,避免意外改變父函數的內部變數。
閉包在數學上也有其應用,比如在離散數學中,關系的閉包是通過添加額外有序對來增強原有關系的性質,而在拓撲學中,閉包概念擴展到鄰域和集合子集的包含關系。總之,閉包是一個強大而復雜的概念,它在編程和數學領域都發揮著重要作用。