搜尋
首頁Javajava教程Java技巧總結如何看Lambda源碼

本篇文章為大家帶來了關於java的相關知識,其中主要介紹了關於如何看Lambda源碼的相關問題,使用Lambda 表達式可以對程式碼進行大量的優化,用幾行程式碼就可以做很多事情,下面一起來看一下,希望對大家有幫助。

Java技巧總結如何看Lambda源碼

推薦學習:《java影片教學

大家都知道Java8 中新增了Lambda 表達式,使用Lambda 表達式可以對程式碼進行大量的最佳化,用幾行程式碼就可以做很多事情,本章以Lambda 為例,第一小節說明一下其底層的執行原理,第二小節說明一下Lambda 流在工作中常用的姿勢。

1、Demo

首先我們來看一個Lambda 表達式的Demo,如下圖:

##程式碼比較簡單,就是新起一個執行緒印一句話,但對於圖中() -> System.out.println ( “ lambda is run “ ) 這種程式碼,估計很多同學都感覺到很困惑,Java 是怎麼識別這種代碼的?

 如果我們修改成匿名內部類別的寫法,就很清楚,大家都能看懂,如下圖:

 那是不是說() -> System.out.println ( “ lambda is run “ ) 這種形式的程式碼,其實就是建立了內部類別呢?其實這就是最簡單 Lambda 表達式,我們是無法透過 IDEA 看到原始碼和其底層結構的,下面我們就來介紹幾種可看到其底層實現的方式。

2、異常判斷法

我們可以在程式碼執行中主動拋出異常,列印出堆疊,堆疊會說明其運行軌跡,一般這種方法簡單高效,基本上可以看到很多情況下的隱藏程式碼,我們來試一下,如下圖:

#從異常的堆疊中,我們可以看到JVM 自動給當前類別建立了內部類(錯誤堆疊中出現多次的$ 表示有內部類別),內部類別的程式碼在執行過程中,拋出了異常,但這裡顯示的程式碼是Unknown Source,所以我們也無法debug 進去,一般情況下,異常都能暴露出程式碼執行的路徑,我們可以打好斷點後再次運行,但對於Lambda 表達式而言,透過異常判斷法我們只清楚有內部類別,但無法看到內部類別中的原始碼。

 3、javap 指令法

 javap 是Java 內建的可以檢視class 字節碼檔案的工具,安裝過Java 基礎環境的電腦都可以直接執行javap 指令,如下圖:

 指令選項中,我們主要是用-v -verbose 這個指令,可以完整輸出字節碼檔的內容。

接下來我們使用 javap 指令查看下 Lambda.class 文件,在講解的過程中,我們會帶一些關於 class 檔案的知識。

我們在指令視窗中找到Lambda.class 所在的位置,執行指令:javap -verbose Lambda.class,然後你會看到一長串的東西,這些叫做彙編指令,接下來我們來一一講解下( 所有的參考資料來自 Java 虛擬機規範,不再一一引用說明):

彙編指令中我們很容易找到Constant pool 打頭的一長串類型,我們叫做常數池,官方英文叫做Run-Time Constant Pool,我們簡單理解成一個裝滿常數的table ,table 中包含編譯時明確的數字和文字,類別、方法和字段的類型資訊等等。 table 中的每個元素叫做cp

info,cpinfo 由唯一識別( tag ) 名稱組成,目前tag 的型別一共有:

Java技巧總結如何看Lambda源碼##貼出我們解析出來的部分圖:

    圖中Constant pool 字樣代表目前資訊是常數池;
  1. 每行都是一個 
  2. cp_info

     ,第一列的#1 代表是在常數池下標示為1 的位置;

  3. 每行的第二列,是 cp_info 的唯一識別( tag ) ,例如Methodref 對應上表中的CONSTANT_Methodref(上圖表格中value 對應10的tag),代表當前行是表示方法的描述資訊的,比如說方法的名稱,入參類型,出參數類型等,具體的含義在Java 虛擬機規範中都可以查詢到,Methodref 的截圖如下:
    Java技巧總結如何看Lambda源碼

  4. 每行的第三列,如果是具體的值的話,直接顯示具體的值,如果是複雜的值的話,會顯示 cp_info  的引用,比如說圖中標紅2 處,引用兩個13 和14 位置的 cp_info,13 表示方法名字是init,14 表示方法無回傳值,結合起來表示方法的名稱而回傳類型,就是一個無參構造子;

  5. 每行的第四列,就是具體的值了。

 對於比較重要的cp_info 類型我們說明下其意義:

  1. InvokeDynamic 表示動態的呼叫方法,後面我們會詳細說明;
  2. Fieldref 表示欄位的描述訊息,如欄位的名稱、類型;
  3. NameAndType 是對欄位和方法類型的描述;
  4. MethodHandle 方法句柄,動態呼叫方法的統稱,在編譯時我們不知道具體是那個方法,但運行時肯定會知道呼叫的是那個方法;
  5. MethodType 動態方法類型,只有在動態運行時才會知道其方法類型是什麼。

 我們從上圖標示紅色的3 處,發現Ljava/lang/invoke/MethodHandles$Lookup,java/lang/invoke/LambdaMetafactory.metafactory 類似這樣的程式碼,MethodHandles 和LambdaMetafactory 都是java.lang.invoke 套件下面的重要方法,invoke 套件主要實現了動態語言的功能,我們知道java 語言屬於靜態編譯語言,在編譯的時候,類別、方法、字段等等的類型都已經確定了,而invoke 實作的是一種動態語言,也就是說編譯的時候不知道類別、方法、欄位是什麼類型,只有到運行的時候才知道。

例如這行程式碼:Runnable runnable = () -> System.out.println(“lambda is run”); 在編譯器編譯的時候() 這個括號編譯器並不知道是做什麼的,只有在運作的時候,才會知道原來這代表的是Runnable.run() 方法。 invoke 套件裡面很多類,都是為了代表這些() 的,我們稱作為方法句柄( MethodHandler ),在編譯的時候,編譯器只知道這裡是個方法句柄,並不知道實際上執行什麼方法,只有在執行的時候才知道,那麼問題來了,JVM 執行的時候,是如何知道() 這個方法句柄,實際上是執行Runnable.run() 方法的呢?

首先我們看下simple 方法的組譯指令:

#從上圖就可以看出simple 方法中的() -> System. out.println(“lambda is run”) 程式碼中的(),其實就是Runnable.run 方法。

我們追溯到# 2 常數池,也就是上上圖中標紅1 處,InvokeDynamic 表示這裡是個動態調用,調用的是兩個常數池的cp_info,位置是#0:#37 ,我們往下找#37 代表著是// run:()Ljava/lang/Runnable,這裡顯示了在JVM 真正執行的時候,需要動態呼叫Runnable.run() 方法,從組譯指令上我們可以看出()其實就是Runnable.run(),下面我們debug 來證明一下。

我們在上上圖3 處發現了LambdaMetafactory.metafactory 的字樣,透過查詢官方文檔,得知該方法正是執行時, 連結到真正程式碼的關鍵,於是我們在metafactory 方法中打個斷點debug 一下,如下圖:

Java技巧總結如何看Lambda源碼

 metafactory 方法入參caller 代表實際發生動態呼叫的位置,invokedName 表示呼叫方法名稱,invokedType 表示呼叫的多個入參和出參,samMethodType 表示具體的實現者的參數,implMethod 表示實際上的實現者,instantiatedMethodType 等同於implMethod。

以上內容總結一下:

1:從組譯指令的simple 方法中,我們可以看到會執行Runnable.run 方法;

2:在實際的運行時,JVM 碰到simple 方法的invokedynamic 指令,會動態呼叫LambdaMetafactory.metafactory 方法,並執行特定的Runnable.run 方法。

所以可以把Lambda 表達值的具體執行歸功於invokedynamic JVM 指令,正是因為這個指令,才可以做到雖然編譯時不知道要幹啥,但動態運行時卻能找到具體要執行的代碼。

接著我們看一下在彙編指令輸出的最後,我們發現了異常判斷法中發現的內部類,如下圖:

Java技巧總結如何看Lambda源碼

 上圖中箭頭很多,一層一層的表達清楚了目前內部類別的所有資訊。

4、總結

 我們總結一下,Lambda 表達式執行主要是依靠invokedynamic 的JVM 指令來實現,咱們演示的類別的全路徑為:demo.eight.Lambda 感興趣的同學可以自己試試看。

 不囉嗦,文章結束,期待三連!

推薦學習:《java影片教學

以上是Java技巧總結如何看Lambda源碼的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文轉載於:CSDN。如有侵權,請聯絡admin@php.cn刪除

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
1 個月前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
1 個月前By尊渡假赌尊渡假赌尊渡假赌
威爾R.E.P.O.有交叉遊戲嗎?
1 個月前By尊渡假赌尊渡假赌尊渡假赌

熱工具

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

這個專案正在遷移到osdn.net/projects/mingw的過程中,你可以繼續在那裡關注我們。 MinGW:GNU編譯器集合(GCC)的本機Windows移植版本,可自由分發的導入函式庫和用於建置本機Windows應用程式的頭檔;包括對MSVC執行時間的擴展,以支援C99功能。 MinGW的所有軟體都可以在64位元Windows平台上運作。

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

WebStorm Mac版

WebStorm Mac版

好用的JavaScript開發工具

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

強大的PHP整合開發環境

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器