中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Scala和Java8怎么寫Lambda表達式

發布時間:2021-12-08 16:59:18 來源:億速云 閱讀:100 作者:iii 欄目:大數據

本篇內容主要講解“Scala和Java8怎么寫Lambda表達式”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“Scala和Java8怎么寫Lambda表達式”吧!

Java的寫法 –

1List names = Arrays.asList("1", "2", "3");

2Stream lengths = names.stream().map(name -> name.length());

Scala的寫法 –

1.val names = List("1", "2", "3")

2.val lengths = names.map(name =>name.length)

表面上看起來非常簡單,那么后面的復雜東西是怎么搞的呢?

一起分析Scala的實現方式

The Code

我使用javap(jdk自帶的工具)去查看Scala編譯器編譯出來的class類中所包含的字節碼內容。讓我們一起看看最終的字節碼(這是JVM將真正執行的)

1.// 加載names對象引用,壓入操作棧(JVM把它當成變量#2)

2.// 它將停留一會,直到被map函數調用.

3.aload_2

接下來的東西變得更加有趣了,編譯器產生的一個合成類的實例被創建和初始化。從JVM角度,就是通過這個對象持有Lambda方法的。有趣的是雖然Lambda被定義為我們方法的一個組成部分,但實際上它完全存在于我們的類之外。

new myLambdas/Lambda1$$anonfun$1 //new一個lambda實例變量.
dup //把lambda實例變量引用壓入操作棧.

// 最后,調用它的構造方法.記住,對于JVM來說,它僅僅只是一個普通對象.
invokespecial myLambdas/Lambda1$$anonfun$1/()V

//這兩行長的代碼加載了用于創建list的immutable.List CanBuildFrom工廠。
//這個工廠模式是Scala集合架構的一部分。
getstatic scala/collection/immutable/List$/MODULE$
Lscala/collection/immutable/List$;
invokevirtual scala/collection/immutable/List$/canBuildFrom()
Lscala/collection/generic/CanBuildFrom;

// 現在我們的操作棧中已經有了Lambda對象和工廠
// 接下來的步驟是調用map函數。
// 如果你記得,我們一開始已經將names對象引用壓入操作棧頂。
// names對象現在被作為map方法調用的實例,
// 它也可以接受Lambda對象和工廠用于生成一個包含字符串長度的新集合。
invokevirtual scala/collection/immutable/List/map(Lscala/Function1;
Lscala/collection/generic/CanBuildFrom;)Ljava/lang/Object;

但是,等等,Lambda對象內部到底發生了什么呢?

Lambda 對象

Lambda類衍生自scala.runtime.AbstractFunction1。通過調用map函數可以多態調用被重寫的apply方法,被重寫的apply方法代碼如下:

aload_0 //加載this對象引用到操作棧
aload_1 //加載字符串參數到操作棧
checkcast java/lang/String //檢查是不是字符串類型

// 調用合成類中重寫的apply方法
invokevirtual myLambdas/Lambda1$$anonfun$1/apply(Ljava/lang/String;)I

//包裝返回值
invokestatic scala/runtime/BoxesRunTime/boxToInteger(I)Ljava/lang/Integer
areturn

真正用于執行length()操作的代碼被嵌套在額外的apply方法中,用于簡單的返回我們所期望的字符串長度。

我們前面走了一段很長的路,終于到這邊了:

aload_1

invokevirtual java/lang/String/length()I

ireturn

對于我們上面寫的簡單的代碼,最后生成了大量的字節碼,一個額外的類和一堆新的方法。當然,這并不意味著會讓我們放棄使用Lambda(我們是在寫scala,不是C)。這僅僅表明了這些結構后面的復雜性.試想Lambda表達式的代碼和復雜的東西將被編譯成復雜的執行鏈。

我預計Java8會以相同的方式實現Lambda,但出人意料的是,他們使用了另一種完全不同的方式。

Java 8 – 新的實現方式

Java8的實現,字節碼比較短,但是做的事情卻很意外。它一開始很簡單地加載names變量,并且調用它的stream方法,但它接下來做的東東就顯得很優雅了.它使用一個Java7加入的一個新指令invokeDynamic去動態地連接lambda函數的真正調用點,從而代替創建一個用于包裝lambda函數的對象.

aload_1 //加載names對象引用,壓入操作棧

//調用它的stream()方法
invokeinterface java/util/List.stream:()Ljava/util/stream/Stream;

//神奇的invokeDynamic指令!
invokedynamic #0:apply:()Ljava/util/function/Function;

//調用map方法
invokeinterface java/util/stream/Stream.map:
(Ljava/util/function/Function;)Ljava/util/stream/Stream;

神奇的InvokeDynamic指令. 這個是JAVA 7新加入的指令,它使得JVM限制少了,并且允許動態語言運行時綁定符號.

動態鏈接. 如果你看到invokedynamic指令,你會發現實際上沒有任何Lambda函數的引用(名為lambda$0),這是因為invokedynamic的設計方式,簡單地說就是lambda的名稱和簽名,如我們的例子-

// 一個名為Lamda$0的方法,獲得一個字符串參數并返回一個Integer對象

lambdas/Lambda1.lambda$0:(Ljava/lang/String;)Ljava/lang/Integer;

他們保存在.class文件中一個單獨的表的條目中,執行invokedynamic時會將#0參數傳給指令指針。這個新的表的確在很多年后的今天首次改變了字節碼規范的結構,這也就需要我們改編Takipi的錯誤分析引擎來配合。

The Lambda code

下面這個字節碼是真正的lambda表達式.然后就是千篇一律地、簡單地加載字符串參數,調用length方法獲得長度,并且包裝返回值.注意它是作為靜態方法編譯的,從而避免了傳遞一個額外的this對象給他,就像我們前面看到的Scala中的做法.

aload_0

invokevirtual java/lang/String.length:()

invokestatic java/lang/Integer.valueOf:(I)Ljava/lang/Integer;

areturn

invokedynamic 方式的另一個優點是,它允許我們使用map函數多態地調用這個方法,而不需要去實例化一個封裝對象或調用重寫的方法.非常酷吧!

到此,相信大家對“Scala和Java8怎么寫Lambda表達式”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

运城市| 灌阳县| 翼城县| 衡阳市| 绍兴市| 蛟河市| 修文县| 长汀县| 石首市| 康平县| 潼关县| 锦州市| 会同县| 麦盖提县| 五莲县| 商洛市| 郸城县| 五华县| 高陵县| 翁牛特旗| 安陆市| 谢通门县| 海晏县| 永年县| 上饶市| 吉水县| 宜都市| 仪征市| 凤台县| 马关县| 无棣县| 广宗县| 彭州市| 德惠市| 揭西县| 西青区| 老河口市| 曲阳县| 鹤壁市| 云南省| 龙口市|