try……catch……finally還有return

關于try……finally問題中return的問題,看到很多面試機經(jīng)有著不同的說法,這里配合javap對字節(jié)碼進行反匯編之后仔細分析一番责嚷。

這是正常場景,try中return的情況:


public classTest1 {
         public static void main(String[] args) {
                   System.out.println(tryReturn());
         }
         static String tryReturn() {
                   String x = "hello";
                   String y = "你好";
                   try {
                            return x;
                   }
                   finally {
                            System.out.println(x);
                            x = "hi";
                            System.out.println(x);
                   }
         }

publictestGit.Test1();
    Code:
       0: aload_0
       1: invokespecial #8                  // Methodjava/lang/Object."":()V
       4: return
  public static void main(java.lang.String[]);
    Code:
       0: getstatic     #16                 // Fieldjava/lang/System.out:Ljava/io/PrintStream;
       3: invokestatic  #22                 // MethodtryReturn:()Ljava/lang/String;
       6: invokevirtual #26                 // Methodjava/io/PrintStream.println:(Ljava/lang/String;)V
       9: return
  static java.lang.String tryReturn();
    Code:
       0: ldc           #34                 // String hello
       2: astore_0
       3: ldc           #36                 // String你好
       5: astore_1
       6: aload_0
       7: astore_3
       8: getstatic     #16                 // Fieldjava/lang/System.out:Ljava/io/PrintStream;
      11: aload_0
      12: invokevirtual #26                 // Methodjava/io/PrintStream.println:(Ljava/lang/String;)V
      15:ldc           #38                 // String hi
      17: astore_0
      18: getstatic     #16                 // Fieldjava/lang/System.out:Ljava/io/PrintStream;
      21: aload_0
      22: invokevirtual #26                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      25: aload_3
      26: areturn                                                       //關注這個指令碼掂铐,它代表return
      27: astore_2
      28: getstatic     #16                 // Fieldjava/lang/System.out:Ljava/io/PrintStream;
      31: aload_0
      32: invokevirtual #26                 // Methodjava/io/PrintStream.println:(Ljava/lang/String;)V
      35: ldc           #38                 // String hi
      37: astore_0
      38: getstatic     #16                 // Fieldjava/lang/System.out:Ljava/io/PrintStream;
      41: aload_0
      42: invokevirtual #26                 // Methodjava/io/PrintStream.println:(Ljava/lang/String;)V
      45: aload_2
      46: athrow
    Exception table:
       from   to  target type
           6    8    27   any
}

首先明確一點罕拂,即使try中return了,try-catch-finally代碼塊也會執(zhí)行到結(jié)尾全陨,所以finally{}中的代碼是一定會被執(zhí)行的爆班。

然后注意字節(jié)碼指令areturn,它代表return辱姨。我們發(fā)現(xiàn)正常情況下柿菩,要return的對象被裝入了一個新的空間astore_3,同時執(zhí)行返回時也是通過aload_3讀取這個拷貝雨涛。換句話說正常情況下枢舶,finally中的代碼對局部變量的操作不會影響返回值,因為要return的變量是try中變量的副本替久。

注意祟辟,這里也是一個坑所在的地方。變量傳遞的時候都是值傳遞侣肄,所以如果變量存放的是指向?qū)ο蟮膔eference,那么這里就會有個問題醇份,雖然我在finally中修改變量的值不會影響返回的結(jié)果稼锅,但是我在finally中對方法要返回的對象進行操作時可以的。注意這段代碼:

publicclass Test1 {
         public static void main(String[] args){
                   System.out.println(tryReturn().getName());
         }
         static A tryReturn() {
                   A a = new A();
                   try {
                            a.setName("beijing");
                            return a;
                   }
                   finally {
                            System.out.println(a.getName());
                            a.setName("shanghai");
                            System.out.println(a.getName());//這里成功將a.name變成了上海僚纷,最后主函數(shù)打印時將顯示上海
                   }
         }
}
classA{
         private String name;
         public void setName(String s) {
                   name = s;
         }
         public String getName() {
                   return name;
         }
}

Finally中的代碼成功修改了a中的成員變量矩距,這是要明確注意的。

最后怖竭,我們討論一下finally中也有return的情況:

這是在finally中加入return的情況

publicclassTest1{
         publicstaticvoidmain(String[] args) {
                   System.out.println(tryReturn());
         }
         staticStringtryReturn() {
                   Stringx= "hello";
                   Stringy= "你好";
                   try{
                            return x;
                   }
                   finally{//這么寫IDE是要給你警告的
                            System.out.println(x);
                            x = "hi";
                            System.out.println(x);
                            return x;
                   }
         }
}

publicclass testGit.Test1 {
  public testGit.Test1();
    Code:
       0: aload_0
       1: invokespecial #8                  // Methodjava/lang/Object."":()V
       4: return
  public static void main(java.lang.String[]);
    Code:
       0: getstatic     #16                 // Fieldjava/lang/System.out:Ljava/io/PrintStream;
       3: invokestatic  #22                 // MethodtryReturn:()Ljava/lang/String;
       6: invokevirtual #26                 // Methodjava/io/PrintStream.println:(Ljava/lang/String;)V
       9: return
  static java.lang.String tryReturn();
    Code:
       0: ldc           #34                 // String hello
       2: astore_0
       3: ldc           #36                 // String你好
       5: astore_1
       6: goto          10
       9: pop
      10: getstatic     #16                 // Fieldjava/lang/System.out:Ljava/io/PrintStream;
      13: aload_0
      14: invokevirtual #26                 // Methodjava/io/PrintStream.println:(Ljava/lang/String;)V
      17: ldc           #38                 // String hi
      19: astore_0
      20: getstatic     #16                 // Fieldjava/lang/System.out:Ljava/io/PrintStream;
      23: aload_0
      24: invokevirtual #26                 // Methodjava/io/PrintStream.println:(Ljava/lang/String;)V
      27: aload_0
      28: areturn
    Exception table:
       from   to  target type
           6    9     9   any
}

注意字節(jié)碼锥债,try中的return被跳過去了。根據(jù)底部Exception table的提示痊臭,try中的代碼塊應該是code:6哮肚、9這兩行。然而并沒有執(zhí)行areturn广匙,而是執(zhí)行了goto直接跳到了finally的部分允趟。換句話說如果try和finally中都有return語句,編譯器會忽視try中的return而選擇finally中的return鸦致。當然如果你try和finally都寫return了潮剪,IDE多半是要給你黃線警告的涣楷。

結(jié)論:

  1. try……catch……finally結(jié)構中,代碼一定會按流程執(zhí)行到結(jié)尾抗碰,當然沒有異常被捕捉到的時候catch里的代碼是不執(zhí)行的狮斗。

  2. 關于finally在return之前還是之后。細扣的話弧蝇,我認為finally中的代碼生效在return之后碳褒,方法結(jié)束之前。這點從ex1中的字節(jié)碼文件中可以看到捍壤。當然如果將return定義成方法結(jié)束的話骤视,finally也的確就是發(fā)生在return之前的。

  3. 關于finally中代碼對返回值的影響鹃觉。簡單地說专酗,如果返回值是基本類型或者string,finally中任何關于局部變量的操作都不會影響到返回值盗扇;如果返回值是在此之外的對象祷肯,請一定注意finally中是可以對對象進行操作的。

  4. 關于try和finally中都有return的情況疗隶。一般說來IDE會提醒你不要這么寫(eclipse和IDEA都會給你警告佑笋,當然編譯器是能接受這種寫法的),如果你這么寫了斑鼻,try中的return語句會被編譯器直接跳過蒋纬。

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市坚弱,隨后出現(xiàn)的幾起案子蜀备,更是在濱河造成了極大的恐慌,老刑警劉巖荒叶,帶你破解...
    沈念sama閱讀 222,627評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件碾阁,死亡現(xiàn)場離奇詭異,居然都是意外死亡些楣,警方通過查閱死者的電腦和手機脂凶,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,180評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來愁茁,“玉大人蚕钦,你說我怎么就攤上這事《旌埽” “怎么了冠桃?”我有些...
    開封第一講書人閱讀 169,346評論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長道宅。 經(jīng)常有香客問我食听,道長胸蛛,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,097評論 1 300
  • 正文 為了忘掉前任樱报,我火速辦了婚禮葬项,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘迹蛤。我一直安慰自己民珍,他們只是感情好,可當我...
    茶點故事閱讀 69,100評論 6 398
  • 文/花漫 我一把揭開白布盗飒。 她就那樣靜靜地躺著嚷量,像睡著了一般。 火紅的嫁衣襯著肌膚如雪逆趣。 梳的紋絲不亂的頭發(fā)上蝶溶,一...
    開封第一講書人閱讀 52,696評論 1 312
  • 那天,我揣著相機與錄音宣渗,去河邊找鬼抖所。 笑死,一個胖子當著我的面吹牛痕囱,可吹牛的內(nèi)容都是我干的田轧。 我是一名探鬼主播,決...
    沈念sama閱讀 41,165評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼鞍恢,長吁一口氣:“原來是場噩夢啊……” “哼傻粘!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起帮掉,我...
    開封第一講書人閱讀 40,108評論 0 277
  • 序言:老撾萬榮一對情侶失蹤抹腿,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后旭寿,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,646評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡崇败,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,709評論 3 342
  • 正文 我和宋清朗相戀三年盅称,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片后室。...
    茶點故事閱讀 40,861評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡缩膝,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出岸霹,到底是詐尸還是另有隱情疾层,我是刑警寧澤,帶...
    沈念sama閱讀 36,527評論 5 351
  • 正文 年R本政府宣布贡避,位于F島的核電站痛黎,受9級特大地震影響予弧,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜湖饱,卻給世界環(huán)境...
    茶點故事閱讀 42,196評論 3 336
  • 文/蒙蒙 一掖蛤、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧井厌,春花似錦蚓庭、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,698評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至墓拜,卻和暖如春港柜,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背撮弧。 一陣腳步聲響...
    開封第一講書人閱讀 33,804評論 1 274
  • 我被黑心中介騙來泰國打工潘懊, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人贿衍。 一個月前我還...
    沈念sama閱讀 49,287評論 3 379
  • 正文 我出身青樓授舟,卻偏偏與公主長得像,于是被迫代替她去往敵國和親贸辈。 傳聞我的和親對象是個殘疾皇子释树,可洞房花燭夜當晚...
    茶點故事閱讀 45,860評論 2 361