<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Java中關(guān)于try、catch、finally中的細(xì)節(jié)分析

          共 9910字,需瀏覽 20分鐘

           ·

          2021-10-08 23:32

          程序員的成長(zhǎng)之路
          互聯(lián)網(wǎng)/程序員/技術(shù)/資料共享?
          關(guān)注


          閱讀本文大概需要 7?分鐘。

          來(lái)自:網(wǎng)絡(luò)

          看了一位博友的一篇文章,講解的是關(guān)于java中關(guān)于try、catch、finally中一些問(wèn)題

          下面看一個(gè)例子(例1),來(lái)講解java里面中try、catch、finally的處理流程

          public?class?TryCatchFinally?{

          ????@SuppressWarnings("finally")
          ????public?static?final?String?test()?{
          ????????String?t?=?"";

          ????????try?{
          ????????????t?=?"try";
          ????????????return?t;
          ????????}?catch?(Exception?e)?{
          ????????????//?result?=?"catch";
          ????????????t?=?"catch";
          ????????????return?t;
          ????????}?finally?{
          ????????????t?=?"finally";
          ????????}
          ????}

          ????public?static?void?main(String[]?args)?{
          ????????System.out.print(TryCatchFinally.test());
          ????}

          }

          首先程序執(zhí)行try語(yǔ)句塊,把變量t賦值為try,由于沒(méi)有發(fā)現(xiàn)異常,接下來(lái)執(zhí)行finally語(yǔ)句塊,把變量t賦值為finally,然后return t,則t的值是finally,最后t的值就是finally,程序結(jié)果應(yīng)該顯示finally,但是實(shí)際結(jié)果為try。

          為什么會(huì)這樣,我們不妨先看看這段代碼編譯出來(lái)的class對(duì)應(yīng)的字節(jié)碼,看虛擬機(jī)內(nèi)部是如何執(zhí)行的。

          我們用javap -verbose TryCatchFinally 來(lái)顯示目標(biāo)文件(.class文件)字節(jié)碼信息

          • 系統(tǒng)運(yùn)行環(huán)境:mac os lion系統(tǒng) 64bit

          • jdk信息:Java(TM) SE Runtime Environment (build 1.6.0_29-b11-402-11M3527) Java HotSpot(TM) 64-Bit Server VM (build 20.4-b02-402, mixed mode)


          編譯出來(lái)的字節(jié)碼部分信息,我們只看test方法,其他的先忽略掉

          public?static?final?java.lang.String?test();
          ??Code:
          ???Stack=1,?Locals=4,?Args_size=0
          ???0:????ldc????#16;?//String?
          ???2:????astore_0
          ???3:????ldc????#18;?//String?try
          ???5:????astore_0
          ???6:????aload_0
          ???7:????astore_3
          ???8:????ldc????#20;?//String?finally
          ???10:????astore_0
          ???11:????aload_3
          ???12:????areturn
          ???13:????astore_1
          ???14:????ldc????#22;?//String?catch
          ???16:????astore_0
          ???17:????aload_0
          ???18:????astore_3
          ???19:????ldc????#20;?//String?finally
          ???21:????astore_0
          ???22:????aload_3
          ???23:????areturn
          ???24:????astore_2
          ???25:????ldc????#20;?//String?finally
          ???27:????astore_0
          ???28:????aload_2
          ???29:????athrow
          ??Exception?table:
          ???from???to??target?type
          ????8????13???Class?java/lang/Exception
          ????8????24???any
          ???19????24???any
          ??LineNumberTable:?
          ???line?5:?0
          ???line?8:?3
          ???line?9:?6
          ???line?15:?8
          ???line?9:?11
          ???line?10:?13
          ???line?12:?14
          ???line?13:?17
          ???line?15:?19
          ???line?13:?22
          ???line?14:?24
          ???line?15:?25
          ???line?16:?28

          ??LocalVariableTable:?
          ???Start??Length??Slot??Name???Signature
          ?????27??????0????t???????Ljava/lang/String;
          ?????10??????1????e???????Ljava/lang/Exception;

          ??StackMapTable:?number_of_entries?=?2
          ???frame_type?=?255?/*?full_frame?*/
          ?????offset_delta?=?13
          ?????locals?=?[?class?java/lang/String?]
          ?????stack?=?[?class?java/lang/Exception?]
          ???frame_type?=?74?/*?same_locals_1_stack_item?*/
          ?????stack?=?[?class?java/lang/Throwable?]

          首先看LocalVariableTable信息,這里面定義了兩個(gè)變量 一個(gè)是t String類型,一個(gè)是e Exception 類型

          接下來(lái)看Code部分

          第[0-2]行,給第0個(gè)變量賦值“”,也就是String t="";

          第[3-6]行,也就是執(zhí)行try語(yǔ)句塊 賦值語(yǔ)句 ,也就是 t = "try";

          第7行,重點(diǎn)是第7行,把第s對(duì)應(yīng)的值"try"付給第三個(gè)變量,但是這里面第三個(gè)變量并沒(méi)有定義,這個(gè)比較奇怪

          第[8-10] 行,對(duì)第0個(gè)變量進(jìn)行賦值操作,也就是t="finally"

          第[11-12]行,把第三個(gè)變量對(duì)應(yīng)的值返回

          通過(guò)字節(jié)碼,我們發(fā)現(xiàn),在try語(yǔ)句的return塊中,return 返回的引用變量(t 是引用類型)并不是try語(yǔ)句外定義的引用變量t,而是系統(tǒng)重新定義了一個(gè)局部引用t’,這個(gè)引用指向了引用t對(duì)應(yīng)的值,也就是try ,即使在finally語(yǔ)句中把引用t指向了值finally,因?yàn)閞eturn的返回引用已經(jīng)不是t ,所以引用t的對(duì)應(yīng)的值和try語(yǔ)句中的返回值無(wú)關(guān)了。

          下面在看一個(gè)例子:(例2)

          public?class?TryCatchFinally?{

          ????@SuppressWarnings("finally")
          ????public?static?final?String?test()?{
          ????????String?t?=?"";

          ????????try?{
          ????????????t?=?"try";
          ????????????return?t;
          ????????}?catch?(Exception?e)?{
          ????????????//?result?=?"catch";
          ????????????t?=?"catch";
          ????????????return?t;
          ????????}?finally?{
          ????????????t?=?"finally";
          ????????????return?t;
          ????????}
          ????}

          ????public?static?void?main(String[]?args)?{
          ????????System.out.print(TryCatchFinally.test());
          ????}

          }

          這里稍微修改了 第一段代碼,只是在finally語(yǔ)句塊里面加入了 一個(gè) return t 的表達(dá)式。

          按照第一段代碼的解釋,先進(jìn)行try{}語(yǔ)句,然后在return之前把當(dāng)前的t的值try保存到一個(gè)變量t',然后執(zhí)行finally語(yǔ)句塊,修改了變量t的值,在返回變量t。

          這里面有兩個(gè)return語(yǔ)句,但是程序到底返回的是try 還是 finally。接下來(lái)我們還是看字節(jié)碼信息

          public?static?final?java.lang.String?test();
          ??Code:
          ???Stack=1,?Locals=2,?Args_size=0
          ???0:????ldc????#16;?//String?
          ???2:????astore_0
          ???3:????ldc????#18;?//String?try
          ???5:????astore_0
          ???6:????goto????17
          ???9:????astore_1
          ???10:????ldc????#20;?//String?catch
          ???12:????astore_0
          ???13:????goto????17
          ???16:????pop
          ???17:????ldc????#22;?//String?finally
          ???19:????astore_0
          ???20:????aload_0
          ???21:????areturn
          ??Exception?table:
          ???from???to??target?type
          ????9?????9???Class?java/lang/Exception
          ???16????16???any
          ??LineNumberTable:?
          ???line?5:?0
          ???line?8:?3
          ???line?9:?6
          ???line?10:?9
          ???line?12:?10
          ???line?13:?13
          ???line?14:?16
          ???line?15:?17
          ???line?16:?20

          ??LocalVariableTable:?
          ???Start??Length??Slot??Name???Signature
          ?????19??????0????t???????Ljava/lang/String;
          ?????6??????1????e???????Ljava/lang/Exception;

          ??StackMapTable:?number_of_entries?=?3
          ???frame_type?=?255?/*?full_frame?*/
          ?????offset_delta?=?9
          ?????locals?=?[?class?java/lang/String?]
          ?????stack?=?[?class?java/lang/Exception?]
          ???frame_type?=?70?/*?same_locals_1_stack_item?*/
          ?????stack?=?[?class?java/lang/Throwable?]
          ???frame_type?=?0?/*?same?*/

          這段代碼翻譯出來(lái)的字節(jié)碼和第一段代碼完全不同,還是繼續(xù)看code屬性

          第[0-2]行、[3-5]行第一段代碼邏輯類似,就是初始化t,把try中的t進(jìn)行賦值try

          第6行,這里面跳轉(zhuǎn)到第17行,[17-19]就是執(zhí)行finally里面的賦值語(yǔ)句,把變量t賦值為finally,然后返回t對(duì)應(yīng)的值

          我們發(fā)現(xiàn)try語(yǔ)句中的return語(yǔ)句給忽略??赡躩vm認(rèn)為一個(gè)方法里面有兩個(gè)return語(yǔ)句并沒(méi)有太大的意義,所以try中的return語(yǔ)句給忽略了,直接起作用的是finally中的return語(yǔ)句,所以這次返回的是finally。

          接下來(lái)在看看復(fù)雜一點(diǎn)的例子:(例3)

          public?class?TryCatchFinally?{

          ????@SuppressWarnings("finally")
          ????public?static?final?String?test()?{
          ????????String?t?=?"";

          ????????try?{
          ????????????t?=?"try";
          ????????????Integer.parseInt(null);
          ????????????return?t;
          ????????}?catch?(Exception?e)?{
          ????????????t?=?"catch";
          ????????????return?t;
          ????????}?finally?{
          ????????????t?=?"finally";
          ????????????//?System.out.println(t);
          ????????????//?return?t;
          ????????}
          ????}

          ????public?static?void?main(String[]?args)?{
          ????????System.out.print(TryCatchFinally.test());
          ????}

          }

          這里面try語(yǔ)句里面會(huì)拋出 java.lang.NumberFormatException,所以程序會(huì)先執(zhí)行catch語(yǔ)句中的邏輯,t賦值為catch,在執(zhí)行return之前,會(huì)把返回值保存到一個(gè)臨時(shí)變量里面t ',執(zhí)行finally的邏輯,t賦值為finally,但是返回值和t',所以變量t的值和返回值已經(jīng)沒(méi)有關(guān)系了,返回的是catch

          例4:

          public?class?TryCatchFinally?{

          ????@SuppressWarnings("finally")
          ????public?static?final?String?test()?{
          ????????String?t?=?"";

          ????????try?{
          ????????????t?=?"try";
          ????????????Integer.parseInt(null);
          ????????????return?t;
          ????????}?catch?(Exception?e)?{
          ????????????t?=?"catch";
          ????????????return?t;
          ????????}?finally?{
          ????????????t?=?"finally";
          ????????????return?t;
          ????????}
          ????}

          ????public?static?void?main(String[]?args)?{
          ????????System.out.print(TryCatchFinally.test());
          ????}

          }

          這個(gè)和例2有點(diǎn)類似,由于try語(yǔ)句里面拋出異常,程序轉(zhuǎn)入catch語(yǔ)句塊,catch語(yǔ)句在執(zhí)行return語(yǔ)句之前執(zhí)行finally,而finally語(yǔ)句有return,則直接執(zhí)行finally的語(yǔ)句值,返回finally

          例5:

          public?class?TryCatchFinally?{

          ????@SuppressWarnings("finally")
          ????public?static?final?String?test()?{
          ????????String?t?=?"";

          ????????try?{
          ????????????t?=?"try";
          ????????????Integer.parseInt(null);
          ????????????return?t;
          ????????}?catch?(Exception?e)?{
          ????????????t?=?"catch";
          ????????????Integer.parseInt(null);
          ????????????return?t;
          ????????}?finally?{
          ????????????t?=?"finally";
          ????????????//return?t;
          ????????}
          ????}

          ????public?static?void?main(String[]?args)?{
          ????????System.out.print(TryCatchFinally.test());
          ????}

          }

          這個(gè)例子在catch語(yǔ)句塊添加了Integer.parser(null)語(yǔ)句,強(qiáng)制拋出了一個(gè)異常。然后finally語(yǔ)句塊里面沒(méi)有return語(yǔ)句。

          繼續(xù)分析一下,由于try語(yǔ)句拋出異常,程序進(jìn)入catch語(yǔ)句塊,catch語(yǔ)句塊又拋出一個(gè)異常,說(shuō)明catch語(yǔ)句要退出,則執(zhí)行finally語(yǔ)句塊,對(duì)t進(jìn)行賦值。然后catch語(yǔ)句塊里面拋出異常。

          結(jié)果是拋出java.lang.NumberFormatException異常

          例子6:

          public?class?TryCatchFinally?{

          ????@SuppressWarnings("finally")
          ????public?static?final?String?test()?{
          ????????String?t?=?"";

          ????????try?{
          ????????????t?=?"try";
          ????????????Integer.parseInt(null);
          ????????????return?t;
          ????????}?catch?(Exception?e)?{
          ????????????t?=?"catch";
          ????????????Integer.parseInt(null);
          ????????????return?t;
          ????????}?finally?{
          ????????????t?=?"finally";
          ????????????return?t;
          ????????}
          ????}

          ????public?static?void?main(String[]?args)?{
          ????????System.out.print(TryCatchFinally.test());
          ????}

          }

          這個(gè)例子和上面例子中唯一不同的是,這個(gè)例子里面finally 語(yǔ)句里面有return語(yǔ)句塊。try catch中運(yùn)行的邏輯和上面例子一樣,當(dāng)catch語(yǔ)句塊里面拋出異常之后,進(jìn)入finally語(yǔ)句快,然后返回t。則程序忽略catch語(yǔ)句塊里面拋出的異常信息,直接返回t對(duì)應(yīng)的值 也就是finally。方法不會(huì)拋出異常

          例子7:

          public?class?TryCatchFinally?{

          ????@SuppressWarnings("finally")
          ????public?static?final?String?test()?{
          ????????String?t?=?"";

          ????????try?{
          ????????????t?=?"try";
          ????????????Integer.parseInt(null);
          ????????????return?t;
          ????????}?catch?(NullPointerException?e)?{
          ????????????t?=?"catch";
          ????????????return?t;
          ????????}?finally?{
          ????????????t?=?"finally";
          ????????}
          ????}

          ????public?static?void?main(String[]?args)?{
          ????????System.out.print(TryCatchFinally.test());
          ????}

          }

          這個(gè)例子里面catch語(yǔ)句里面catch的是NPE異常,而不是java.lang.NumberFormatException異常,所以不會(huì)進(jìn)入catch語(yǔ)句塊,直接進(jìn)入finally語(yǔ)句塊,finally對(duì)s賦值之后,由try語(yǔ)句拋出java.lang.NumberFormatException異常。

          例子8

          public?class?TryCatchFinally?{

          ????@SuppressWarnings("finally")
          ????public?static?final?String?test()?{
          ????????String?t?=?"";

          ????????try?{
          ????????????t?=?"try";
          ????????????Integer.parseInt(null);
          ????????????return?t;
          ????????}?catch?(NullPointerException?e)?{
          ????????????t?=?"catch";
          ????????????return?t;
          ????????}?finally?{
          ????????????t?=?"finally";
          ????????????return?t;
          ????????}
          ????}

          ????public?static?void?main(String[]?args)?{
          ????????System.out.print(TryCatchFinally.test());
          ????}

          }

          和上面的例子中try catch的邏輯相同,try語(yǔ)句執(zhí)行完成執(zhí)行finally語(yǔ)句,finally賦值s 并且返回s ,最后程序結(jié)果返回finally

          例子9:

          public?class?TryCatchFinally?{

          ????@SuppressWarnings("finally")
          ????public?static?final?String?test()?{
          ????????String?t?=?"";

          ????????try?{
          ????????????t?=?"try";return?t;
          ????????}?catch?(Exception?e)?{
          ????????????t?=?"catch";
          ????????????return?t;
          ????????}?finally?{
          ????????????t?=?"finally";
          ????????????String.valueOf(null);
          ????????????return?t;
          ????????}
          ????}

          ????public?static?void?main(String[]?args)?{
          ????????System.out.print(TryCatchFinally.test());
          ????}

          }

          這個(gè)例子中,對(duì)finally語(yǔ)句中添加了String.valueOf(null), 強(qiáng)制拋出NPE異常。首先程序執(zhí)行try語(yǔ)句,在返回執(zhí)行,執(zhí)行finally語(yǔ)句塊,finally語(yǔ)句拋出NPE異常,整個(gè)結(jié)果返回NPE異常。

          對(duì)以上所有的例子進(jìn)行總結(jié)

          1. try、catch、finally語(yǔ)句中,在如果try語(yǔ)句有return語(yǔ)句,則返回的之后當(dāng)前try中變量此時(shí)對(duì)應(yīng)的值,此后對(duì)變量做任何的修改,都不影響try中return的返回值

          2. 如果finally塊中有return 語(yǔ)句,則返回try或catch中的返回語(yǔ)句忽略。

          3. 如果finally塊中拋出異常,則整個(gè)try、catch、finally塊中拋出異常


          所以使用try、catch、finally語(yǔ)句塊中需要注意的是

          1. 盡量在try或者catch中使用return語(yǔ)句。通過(guò)finally塊中達(dá)到對(duì)try或者catch返回值修改是不可行的。

          2. finally塊中避免使用return語(yǔ)句,因?yàn)閒inally塊中如果使用return語(yǔ)句,會(huì)顯示的消化掉try、catch塊中的異常信息,屏蔽了錯(cuò)誤的發(fā)生

          3. finally塊中避免再次拋出異常,否則整個(gè)包含try語(yǔ)句塊的方法回拋出異常,并且會(huì)消化掉try、catch塊中的異常


          推薦閱讀:
          真給 IT 人丟臉??!
          用 Java 開(kāi)發(fā)一個(gè)打飛機(jī)小游戲(附完整源碼)

          最近面試BAT,整理一份面試資料《Java面試BATJ通關(guān)手冊(cè)》,覆蓋了Java核心技術(shù)、JVM、Java并發(fā)、SSM、微服務(wù)、數(shù)據(jù)庫(kù)、數(shù)據(jù)結(jié)構(gòu)等等。

          獲取方式:點(diǎn)個(gè)「在看」,點(diǎn)擊上方小卡片,進(jìn)入公眾號(hào)后回復(fù)「面試題」領(lǐng)取,更多內(nèi)容陸續(xù)奉上。

          朕已閱?

          瀏覽 57
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  免费看黄色视频久久 | 黄色一级免费看 | 中文字幕一区视频 | 蜜桃久久久久 | 啪啪啪视频官网 |