Java JDK1.8新特性Lambda 表示式
一、lambda含義
lambda表示數學符號“λ”,計算機領域中λ代表“λ演算”,表達了計算機中最基本的概念:“呼叫”和“置換”。在很多動態語言和C#中都有相應的lambda語法,這類語法都為了簡化程式碼,提高執行效率。
二、lambda 專案的背景,參考這裡。
無論是面嚮物件語言還是函式式語言,基本數值都可以被動態的封裝入程式動作:面嚮物件語言通過“方法”,函式式語言通過“函式。
介於“方法”和“函式”的定義有很多種,補充下IBM知識庫的解釋:
在面嚮物件語言中,方法不是一階值(First-class value),在函式式語言中,函式是一階值。在函式式語言中,函式可以作為另一個函式的返回值或引數,還可以作為一個變數的值,函式可以巢狀定義,而在面嚮物件語言中的的“方法”做不到這點。
Java可以說是面嚮物件語言的代表,如果要呼叫其方法,需要先建立物件。不過Java物件都是“重量級”的,例項化具體的類的物件,需要經過定義和申明兩個階段。比如定義方法,並給內部欄位賦初始值。但是一個物件只包含一個方法的情況很多,比如實現API中的“回撥介面”功能的類,在swing中有介面:
Java程式碼- <span><span><span style="">public interface ActionListener {
- void actionPerformed(ActionEvent e);
-
}</span></span></span>
現有的實現方式大多是:
Java程式碼- <span><span><span style="">button.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- ui.dazzle(e.getModifiers());
- }
- });</span></span></span>
很多現有的類庫都基於這種設計實現,所以對於程式碼被明確定義執行在單獨執行緒的API來說,匿名內部類尤為重要。這些匿名內部類只存在於建立它的執行緒中。但是在平行計算領域,CPU的製造商著力發展多核技術來提升CPU的功能,這麼做幾乎無法依靠多核的優勢來提升其效能。
鑑於回撥函式和其他功能式語法的關係越來越密切,所以必須建立儘可能的輕量級的資料模型(從編碼角度而言,效能方面下文再說)。對於這點來說匿名內部類的缺點如下:
1.語法相對複雜。
2.在呼叫內部類的上下文中,指引和this的指代容易混淆。
3.類載入和例項建立語法不可避免。
4.不能引用外部的非final物件。
5.不能抽象化控制流程
針對這些問題,lambda專案致力於
1. 消除問題1和問題2,通過引入更簡單的表示式和區域性變數的定義規則。
2. 迴避問題3,定義更靈活更友善的語法。這裡只是迴避,類載入和例項化本身不可避免。下文會解釋。
3. 改善問題4,允許使用者使用最終有效的區域性變數。
不過lambda專案目前並不能解決所有關於內部類的問題。問題4和問題5沒有完全解決,這計劃在將類版本中繼續改善。對於效能方面,原文也沒有提,不過後面有些補充。
三、lambda用法
通過上文可以瞭解到,lambda語法是針對“回撥介面”和“匿名內部類”作出的改進,所以lambda的語法目前僅對於部分介面,這些介面的特點是隻含一個抽象方法,在lambda專案中,早期稱為SAM型別(SAM = single abstract method 即單一抽象方法)。在最新的文件中(即這個版本),它們有了新名字,叫函式介面(functional interface),比如:
1java.lang.Runnable 2java.util.concurrent.Callable 3java.security.PrivilegedAction 4java.util.Comparator 5java.io.FileFilter 6java.nio.file.PathMatcher 7java.lang.reflect.InvocationHandler 8java.beans.PropertyChangeListener 9java.awt.event.ActionListener 10javax.swing.event.ChangeListener lambda的語法包括三部分 1、引數列表 2、箭頭符號"->" 3、程式碼塊。其中程式碼塊很像一個方法體,return語句將控制權交還給匿名方法(anonymous method,即lambda表示式)的呼叫者;break和continue不能出現在函式體的頂部,不過可以出現在內部的迴圈裡;如果程式碼塊得出最終結果,那麼每一個控制路徑(control path) 必須都有返回或丟擲異常。
如果程式碼塊只有簡單一行,可以省略return關鍵字和“{}”符號(以下所寫的例子都是基於JDK 1.8 lambda預覽版),比如:
Java程式碼- <span><span><span style="">public class LambdaTest {
- public static void main(String... args) {
- //這裡有{}和return 以及 ;
- Runnable r = () -> { System.out.println("hello world"); };
- //這裡不需要{}和return
- java.util.Comparator<String> c = (String s1, String s2) -> s2.length()-s1.length();
- r.run();
- System.out.println(c.compare("s1", "12323"));
- }
- }</span></span></span>
輸出為:
hello world
3
除了這些現有介面,我們還可以自定義函式介面:
Java程式碼- <span><span><span style="">public class LambdaTest {
- interface lambdaInterface {
- public void me(String str);
- }
- public static void main(String... args) {
- lambdaInterface li = (String s)->{System.out.println(s);};
- li.me("hello world!");
- }
- }</span></span></span>
輸出為:
hello world!
新的lambda方法從語法上的確是簡化了很多。和lambda第一次釋出的語法相比也優雅很多。
四、lambda程式碼塊的位元組碼
看完了語法的確很簡單,那麼lambda是怎麼實現的,就得從位元組碼考察了。這裡和匿名內部類做個對比,編譯如下程式碼:
Java程式碼- <span><span><span style="">public class LambdaTest {
- lambdaInterface li1 = ()->{System.out.println(this);};
- lambdaInterface li2 = new lambdaInterface(){
- public void me(){
- System.out.println(this);
- }
- };
- public static void main(String... args) {
- LambdaTest lt = new LambdaTest();
- lt.li1.me();
- lt.li2.me();
- }
- }
- interface lambdaInterface {
- public void me();
- }</span></span></span>
編譯後有會有四個檔案:
LambdaTest.class
LambdaTest$1.class
LambdaTest$2.class
lambdaInterface.class
它的的輸出結果為:
結果很明顯地顯示,lambda程式碼塊和內部類的this的指引是不一樣的。lambda程式碼塊輸出的是呼叫者的this,即lambdaTest.class的例項。匿名內部類輸出的是自己lambdaTest$1.class的例項。
先看看lambdaTest.class的位元組碼:
Txt程式碼- <span><span><span style="">public class LambdaTest {
- lambdaInterface li1;
- lambdaInterface li2;
- public LambdaTest();
- Code:
- 0: aload_0
- 1: invokespecial #1 // Method java/lang/Object."<init>":()V
- 4: aload_0
- 5: new #2 // class LambdaTest$2
- 8: dup
- 9: aload_0
- 10: aload_0
- 11: invokespecial #3 // Method LambdaTest$2."<init>":(LLambdaTest;LLambdaTest;)V
- 14: putfield #4 // Field li1:LlambdaInterface;
- 17: aload_0
- 18: new #5 // class LambdaTest$1
- 21: dup
- 22: aload_0
- 23: invokespecial #6 // Method LambdaTest$1."<init>":(LLambdaTest;)V
- 26: putfield #7 // Field li2:LlambdaInterface;
- 29: return
- public static void main(java.lang.String...);
- Code:
- 0: new #8 // class LambdaTest
- 3: dup
- 4: invokespecial #9 // Method "<init>":()V
- 7: astore_1
- 8: aload_1
- 9: getfield #4 // Field li1:LlambdaInterface;
- 12: invokeinterface #10, 1 // InterfaceMethod lambdaInterface.me:()V
- 17: aload_1
- 18: getfield #7 // Field li2:LlambdaInterface;
- 21: invokeinterface #10, 1 // InterfaceMethod lambdaInterface.me:()V
- 26: return
- }</span></span></span>
從這裡可以看出,lambda程式碼塊和匿名內部類的呼叫方法是一樣的,都是先建立一個方法,然後建立其控制代碼,這兩個控制代碼分別對應lambdaTest$2.class和lambdaTest$1.class。
其中匿名內部類對應LambdaTest$1,它的位元組碼為:
Txt程式碼- <span><span><span style="">class LambdaTest$1 implements lambdaInterface {
- final LambdaTest this$0;
- LambdaTest$1(LambdaTest);
- Code:
- 0: aload_0
- 1: aload_1
- 2: putfield #1 // Field this$0:LLambdaTest;
- 5: aload_0
- 6: invokespecial #2 // Method java/lang/Object."<init>":()V
- 9: return
- public void me();
- Code:
- 0: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
- 3: aload_0
- 4: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
- 7: return
- }</span></span></span>
lambda程式碼塊對應LambdaTest$2,它的位元組碼為:
Txt程式碼相關推薦
Java JDK1.8新特性Lambda 表示式
一、lambda含義 lambda表示數學符號“λ”,計算機領域中λ代表“λ演算”,表達了計算機中最基本的概念:“呼叫”和“置換”。在很多動態語言和C#中都有相應的lambda語法,這類語法都為了簡化程式碼,提高執行效率。 二、lambda 專案的背景,參考
java1.8新特性-lambda表示式
什麼是lambda表示式 長期以來,java為了保持簡單性和一致性,拒絕給變數賦值成“一段程式碼”,如果你想把“一段程式碼”賦給一個Java變數,應該怎麼做呢?這個“一段程式碼”就是lambda表示式。 為什麼引入lambda表示式 lambo表示式是一個可傳
java1.8 新特性 - Lambda表示式
排序介面優化 先來體驗一下lambda最直觀的優點:簡潔程式碼 //匿名內部類 Comparator<Integer> cpt = new Comparator<Integer>() { &nbs
JDK1.8新特性(二)Lambda表示式入門
lambda表示式本質是匿名方法,下面是一些lambda表示式: (int x, int y) -> x + y () -> 42 (String s) -> { System.out.println(s); } 第一個lambda表示式接收x和y這兩個整形引
Java--8--新特性--Lambda
value 需要 員工信息 span final oid function get test java9 都出來了,我才開始接觸到java8的新特性,有點脫節啊。。 Lambda是一個匿名函數,可以理解為一段可以傳遞的代碼,將代碼像數據一樣傳遞,下面是一個小例子。 pub
Java 8 新特性 - Lambda表達式(一)
ava 鏈接 article post lambda targe dash lambda表達式 java8 鏈接 Java8新特性——Lambda表達式(一)Java 8 新特性 - Lambda表達式(一)
jdk1.8新特性之lambda表達式
rest 簡潔 cnblogs ensure 1.8 可能 finish main RF lambda表達式其實就是指一個匿名函數,應用最廣泛的就是匿名內部類。在jdk1.8之前,我們定義一個匿名內部類可能需要寫一大坨代碼,現在有了lambda之後,可以寫的很簡潔了。但
Java基礎入門之jdk1.8新特性
Lamda 表示式(目標型別) 簡介 語法糖,也叫糖衣語法 指的是計算機中 新增某種語法 這種語法 ,能使程式設計師更加方便的使用語言開發程式,同時,增強了程式碼的可讀性 避免了出錯的機會,但是,這種語法對於語言的功能並且有增強 例如: 泛型 自動裝箱拆箱 增強
Java基礎(五):JDK1.8新特性
JDK1.8新特性 lambda表示式 Lambda lambda作用:lambda是一個語法糖,簡化匿名內部類的使用。 lambda使用條件 引數或者變數必須是介面 介面中只包含一個抽象方法 lambda格式 (引數型別 引數名稱 …)-> { 程
Java還要再學一遍基礎(四)JDK1.8新特性default,static
JDK1.8新特性default,static用法 在1.8以前,我們的Interface之中通常除了抽象方法別的什麼都沒有,但是從1.8引入開始Interface中還可以有具體的實現!其中所要用到的兩個非常重要的關鍵字就是:default和static
Java日期學習筆記(二):JDK1.8新特性
Java 8另一個新增的重要特性就是引入了新的時間和日期API,它們被包含在java.time包中。藉助新的時間和日期API可以以更簡潔的方法處理時間和日期。 在介紹本篇文章內容之前,我們先來討論Java 8為什麼要引入新的日期API,與之前的時間和日期處理方式有什麼不同?
jdk1.8新特性 : 接口中可以有普通方法(非靜態方法)和靜態方法 , 顛覆了之前我的理解 : 接口中只能有共有常量和抽象方法的概念,後面必須要加一句jdk1.7和1..7之前
@override 編譯 sys 接口 blank new style nts highlight 看到jdk某些接口中存在default方法,於是... http://shaomeng95.iteye.com/blog/998820 為什麽接口只能是公有常量? p
jdk1.8新特性之接口default方法
sent arguments sel 可能 beyond lar iter none 裏的 眾所周知,default是java的關鍵字之一,使用場景是配合switch關鍵字用於條件分支的默認項。但自從java的jdk1.8橫空出世以後,它就被賦予了另一項很酷的能力——在
jdk1.8新特性應用之Iterable
accep sub 抽象 default describe dem generate using 操作 我們繼續看lambda表達式的應用: public void urlExcuAspect(RpcController controller, Message
jdk1.7/jdk1.8新特性
在面試中經常會問jdk1.6,jdk1.7,jdk1.8的區別: 最近面試的時候的面試官問我jdk8的新特性: 我回答了幾個,他提問到:為什麼defualt沒有被推廣,有什麼弊端。 我很蒙圈,在這裡新增下回答: 我目前還不知道 jdk1.7新增特性: 1.7新特性轉載 1 s
(Java)jdk-8 - 新特性 - 介面
介面: Java 8允許我們給介面新增一個非抽象的方法實現,只需要使用default關鍵字即可,這個又叫做擴充套件方法 注意:現在介面還可以【存在靜態方法】,可以使用 介面名.靜態方法名 的形式直接呼叫。 例子: public class Test{ public static
jdk8 新特性lambda表示式
首先說明下,jdk8的新特性forEach,Stream在遍歷集合時,程式碼看上去簡潔些,但效率會變低 好了,今天開始介紹新特性,先說lambda表示式 Python裡有個匿名函式,用lambda定義,jdk8的lambda表示式就相當於一個匿名函式,只是功能強大一些 先說一個概念:
java8新特性 (Lambda表示式)
1:lambda表示式入門 提供的介面有四種: ->Function<T,R>接
Jdk1.8新特性
Lambda表示式:Lambda 允許把函式作為一個方法的引數(函式作為引數傳遞進方法中)。可以使程式碼變的更加簡潔緊湊。 Lambda表示式的實質其實還是匿名內部類,而匿名內部類在訪問外部區域性變數時,要求變數必須宣告為final!不過我們在使用Lambda表示
三、java8新特性 lambda表示式在stream中的應用
1.關於JSR335 JSR是Java Specification Requests的縮寫,意思是Java 規範請求,Java 8 版本的主要改進是 Lambda 專案(JSR 335),其目的是使 Java 更易於為多核處理器編寫程式碼。JSR 335=lambda表示式