日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 >

好难啊……一个 try-catch 问出这么多花样

發(fā)布時(shí)間:2024/8/23 45 豆豆
生活随笔 收集整理的這篇文章主要介紹了 好难啊……一个 try-catch 问出这么多花样 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

作者 | 阿Q

來源 |?阿Q說代碼

剛剛面試回來的B哥又在吐槽了:現(xiàn)在的面試官太難伺候了,放著好好的堆、棧、方法區(qū)不問,上來就讓我從字節(jié)碼角度給他分析一下try-catch-finally(以下簡稱TCF)的執(zhí)行效率.....

今天我們就來好好總結(jié)一下~

環(huán)境準(zhǔn)備:IntelliJ IDEA 2020.2.3、JDK 1.8.0_181

執(zhí)行順序

我們先來寫一段簡單的代碼:

public?static?int?test1()?{int?x?=?1;try?{return?x;}?finally?{x?=?2;} }

答案是1不是2,你答對了嗎?

大家都知道在TCF中,執(zhí)行到return的時(shí)候會(huì)先去執(zhí)行finally中的操作,然后才會(huì)返回來執(zhí)行return,那這里為啥會(huì)是1呢?我們來反編譯一下字節(jié)碼文件。

命令:javap -v xxx.class

字節(jié)碼指令晦澀難懂,那我們就用圖解的方式來解釋一下(我們先只看前7行指令):首先執(zhí)行 int x = 1;

然后我們需要執(zhí)行try中的return x;

此時(shí)并不是真正的返回x的值,而是將x的值存到局部變量表中作為臨時(shí)存儲(chǔ)變量進(jìn)行存儲(chǔ),也就是對該值進(jìn)行保護(hù)操作。

最后進(jìn)入finally中執(zhí)行x=2;

此時(shí)雖然x已經(jīng)被賦值為2了,但是由于剛才的保護(hù)操作,在執(zhí)行真正的return操作時(shí),會(huì)將被保護(hù)的臨時(shí)存儲(chǔ)變量入棧返回。

為了更好的理解上述操作,我們再來寫一段簡單代碼:

public?static?int?test2()?{int?x?=?1;try?{return?x;}?finally?{x?=?2;return?x;} }

大家思考一下執(zhí)行結(jié)果是幾?答案是2不是1。

我們再來看下該程序的字節(jié)碼指令

通過對比發(fā)現(xiàn),第6行一個(gè)是iload_1,一個(gè)是iload_0,這是由什么決定的呢?原因就是我們上邊提到的保護(hù)機(jī)制,當(dāng)在finally中存在return語句時(shí),保護(hù)機(jī)制便會(huì)失效,轉(zhuǎn)而將變量的值入棧并返回。

小結(jié)

  • return的執(zhí)行優(yōu)先級(jí)高于finally的執(zhí)行優(yōu)先級(jí),但是return語句執(zhí)行完畢之后并不會(huì)馬上結(jié)束函數(shù),而是將結(jié)果保存到棧幀中的局部變量表中,然后繼續(xù)執(zhí)行finally塊中的語句;

  • 如果finally塊中包含return語句,則不會(huì)對try塊中要返回的值進(jìn)行保護(hù),而是直接跳到finally語句中執(zhí)行,并最后在finally語句中返回,返回值是在finally塊中改變之后的值;

finally 為什么一定會(huì)執(zhí)行

細(xì)心地小伙伴應(yīng)該能發(fā)現(xiàn),上邊的字節(jié)碼指令圖中第4-7行和第9-12行的字節(jié)碼指令是完全一致的,那么為什么會(huì)出現(xiàn)重復(fù)的指令呢?

首先我們來分析一下這些重復(fù)的指令都做了些什么操作,經(jīng)過分析發(fā)現(xiàn)它們就是x = 2;return x;的字節(jié)碼指令,也就是finally代碼塊中的代碼。由此我們有理由懷疑如果上述代碼中加入catch代碼塊,finally代碼塊對應(yīng)的字節(jié)碼指令也會(huì)再次出現(xiàn)。

public?static?int?test2()?{int?x?=?1;try?{return?x;}?catch(Exception?e)?{x?=?3;}?finally?{x?=?2;return?x;} }

反編譯之后

果然如我們所料,重復(fù)的字節(jié)碼指令出現(xiàn)了三次。讓我們回歸到最初的問題上,為什么finally代碼的字節(jié)碼指令會(huì)重復(fù)出現(xiàn)三次呢?

原來是JVM為了保證所有異常路徑和正常路徑的執(zhí)行流程都要執(zhí)行finally中的代碼,所以在try和catch后追加上了finally中的字節(jié)碼指令,再加上它自己本身的指令,正好三次。這也就是為什么finally 一定會(huì)執(zhí)行的原因。

finally一定會(huì)執(zhí)行嗎?

為什么上邊已經(jīng)說了finally中的代碼一定會(huì)執(zhí)行,現(xiàn)在還要再多此一舉呢?請👇看

在正常情況下,它是一定會(huì)被執(zhí)行的,但是至少存在以下三種情況,是一定不執(zhí)行的:

  • try語句沒有被執(zhí)行到就返回了,這樣finally語句就不會(huì)執(zhí)行,這也說明了finally語句被執(zhí)行的必要而非充分條件是:相應(yīng)的try語句一定被執(zhí)行到;

  • try代碼塊中有System.exit(0);這樣的語句,因?yàn)镾ystem.exit(0);是終止JVM的,連JVM都停止了,finally肯定不會(huì)被執(zhí)行了;

  • 守護(hù)線程會(huì)隨著所有非守護(hù)線程的退出而退出,當(dāng)守護(hù)線程內(nèi)部的finally的代碼還未被執(zhí)行到,非守護(hù)線程終結(jié)或退出時(shí),finally 肯定不會(huì)被執(zhí)行;

TCF 的效率問題

說起TCF的效率問題,我們不得不介紹一下異常表,拿上邊的程序來說,反編譯class文件后的異常表信息如下:

  • from:代表異常處理器所監(jiān)控范圍的起始位置;

  • to:代表異常處理器所監(jiān)控范圍的結(jié)束位置(該行不被包括在監(jiān)控范圍內(nèi),是前閉后開區(qū)間);

  • target:指向異常處理器的起始位置;

  • type:代表異常處理器所捕獲的異常類型;

圖中每一行代表一個(gè)異常處理器

工作流程:

  • 觸發(fā)異常時(shí),JVM會(huì)從上到下遍歷異常表中所有的條目;

  • 比較觸發(fā)異常的行數(shù)是否在from-to范圍內(nèi);

  • 范圍匹配之后,會(huì)繼續(xù)比較拋出的異常類型和異常處理器所捕獲的異常類型type是否相同;

  • 如果類型相同,會(huì)跳轉(zhuǎn)到target所指向的行數(shù)開始執(zhí)行;

  • 如果類型不同,會(huì)彈出當(dāng)前方法對應(yīng)的java棧幀,并對調(diào)用者重復(fù)操作;

  • 最壞的情況下JVM需要遍歷該線程 Java 棧上所有方法的異常表;

  • 拿第一行為例:如果位于2-4行之間的命令(即try塊中的代碼)拋出了Class java/lang/Exception類型的異常,則跳轉(zhuǎn)到第8行開始執(zhí)行。

    8: astore_1是指將拋出的異常對象保存到局部變量表中的1位置處

    從字節(jié)碼指令的角度來講,如果代碼中沒有異常拋出,TCF的執(zhí)行時(shí)間可以忽略不計(jì);如果代碼執(zhí)行過程中出現(xiàn)了上文中的第6條,那么隨著異常表的遍歷,更多的異常實(shí)例被構(gòu)建出來,異常所需要的棧軌跡也在生成。該操作會(huì)逐一訪問當(dāng)前線程的棧幀,記錄各種調(diào)試信息,包括類名、方法名、觸發(fā)異常的代碼行數(shù)等等。所以執(zhí)行效率會(huì)大大降低。

    看到這兒,你是否對TCF有了更加深入的了解呢?

    往期推薦

    為什么還有這么多的網(wǎng)絡(luò)故障?

    k8s集群居然可以圖形化安裝了?

    用了HTTPS,沒想到還是被監(jiān)控了

    將 k8s 制作成 3D 射擊游戲,好玩到停不下來

    點(diǎn)分享

    點(diǎn)收藏

    點(diǎn)點(diǎn)贊

    點(diǎn)在看

    總結(jié)

    以上是生活随笔為你收集整理的好难啊……一个 try-catch 问出这么多花样的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。