最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

關(guān)于Java中try finally return語句的執(zhí)行順序淺析

 更新時間:2017年08月23日 10:11:19   作者:麥田  
這篇文章主要介紹了關(guān)于Java中try finally return語句的執(zhí)行順序淺析,需要的朋友可以參考下

問題分析

finally語句塊一定會執(zhí)行嗎?

可能很多人第一反應(yīng)是肯定要執(zhí)行的,但仔細一想,如果一定會執(zhí)行的話 也就不會這么SB的問了。

Demo1

public class Test {
  public static void main(String[] args) {
    System.out.println("return value of test(): " + test());
  }
  public static int test() {
    int i = 1;
    // if (i == 1) {
    // return 0;
    // }
    System.out.println("the previous statement of try block");
    i = i / 0;
    try {
      System.out.println("try block");
      return i;
    } finally {
      System.out.println("finally block");
    }
  }
}

Demo1的執(zhí)行結(jié)果如下:

the previous statement of try block
Exception in thread "main" java.lang.ArithmeticException: / by zero
  at com.becoda.bkms.bus.basics.web.Test2.test(Test2.java:15)
  at com.becoda.bkms.bus.basics.web.Test2.main(Test2.java:5)

另外,如果去掉上例中的注釋,執(zhí)行結(jié)果則是:

return value of test(): 0

以上兩種情況,finally語句塊都沒有執(zhí)行,說明什么問題?只有與finally相對應(yīng)的try語句塊得到執(zhí)行的情況下,finally語句塊才會執(zhí)行,而上面都是在try語句塊之前返回(return)或者拋出異常,所以try對應(yīng)的finally語句塊沒有執(zhí)行。那么,即使與finally相對應(yīng)的try語句塊得到執(zhí)行的情況下,finally語句塊一定會執(zhí)行嗎?但下面例子

Demo2

public class Test {
  public static void main(String[] args) {
    System.out.println("return value of test(): " + test());
  }
  public static int test() {
    int i = 1;
    try {
      System.out.println("try block");
      System.exit(0);
      return i;
    } finally {
      System.out.println("finally block");
    }
  }
}

Demo2的執(zhí)行結(jié)果如下:

try block

finally語句塊還是沒有執(zhí)行,為什么呢?因為我們在try語句塊中執(zhí)行了System.exit(0)語句,終止了Java虛擬機的運行,雖然一般情況下我們不會這么干。還有情況是當(dāng)一個線程在執(zhí)行try語句塊或者catch語句塊時被打斷(interrupted)或者被終止(killed),與其對應(yīng)的finally語句塊可能不會執(zhí)行。還有更極端的情況,就是在線程運行 try 語句塊或者 catch 語句塊時,突然死機或者斷電,finally 語句塊肯定不會執(zhí)行了。

finally 語句示例說明

下面看一個簡單的例子

Demo3

public class Test {
  public static void main(String[] args) {
    try {
      System.out.println("try block");
      return;
    } finally {
      System.out.println("finally block");
    }
  }
}

Demo3的執(zhí)行結(jié)果為:

try block
finally block

Demo3說明 finally 語句塊在 try 語句塊中的 return 語句之前執(zhí)行。我們再來看另一個例子。

Demo4

public class Test {
  public static void main(String[] args) {
    System.out.println("reture value of test() : " + test());
  }
  public static int test() {
    int i = 1;
    try {
      System.out.println("try block");
      i = 1 / 0;
      return 1;
    } catch (Exception e) {
      System.out.println("exception block");
      return 2;
    } finally {
      System.out.println("finally block");
    }
  }
}

Demo4的執(zhí)行結(jié)果為:

try block
exception block
finally block
reture value of test() : 2

Demo4說明了 finally 語句塊在 catch 語句塊中的 return 語句之前執(zhí)行。

從上面的Demo3和Demo4,我們可以看出,其實finally語句塊時在try或者catch中的return語句之前執(zhí)行的,更加一般的說法是,finally語句塊應(yīng)該是在控制轉(zhuǎn)移語句之前執(zhí)行,控制轉(zhuǎn)移語句除了return外,還有break和continue。

再來看下面兩個例子

Demo5

public class Test {
  public static void main(String[] args) {
    System.out.println("return value of getValue(): " + getValue());
  }
  public static int getValue() {
    try {
      return 0;
    } finally {
      return 1;
    }
  }
}

Demo5的執(zhí)行結(jié)果為:

return value of getValue(): 1

Demo6

public class Test {
  public static void main(String[] args) {
    System.out.println("return value of getValue(): " + getValue());
  }
  public static int getValue() {
    int i = 1;
    try {
      return i;
    } finally {
      i++;
    }
  }
}

Demo6的執(zhí)行結(jié)果為:

return value of getValue(): 1

利用我們上面分析得出的結(jié)論:finally 語句塊是在 try 或者 catch 中的 return 語句之前執(zhí)行的。 由此,可以輕松的理解Demo5 的執(zhí)行結(jié)果是 1。因為 finally 中的 return 1;語句要在 try 中的 return 0;語句之前執(zhí)行,那么 finally 中的 return 1;語句執(zhí)行后,把程序的控制權(quán)轉(zhuǎn)交給了它的調(diào)用者 main()函數(shù),并且返回值為 1。那為什么Demo6 的返回值不是 2,而是 1 呢?按照Demo5 的分析邏輯,finally 中的 i++;語句應(yīng)該在 try 中的 return i;之前執(zhí)行???i 的初始值為 1,那么執(zhí)行 i++;之后為 2,再執(zhí)行 return i;那不就應(yīng)該是 2 嗎?怎么變成 1 了呢?

說明這個問題需要了解Java虛擬機是如何編譯finally語句塊的。

Java方法是在棧幀中執(zhí)行,棧幀是線程私有棧的單位,執(zhí)行方法的線程會為每一個方法分配一小塊空間來作為該方法執(zhí)行時的內(nèi)存空間,棧幀分為三個區(qū)域:

1、操作數(shù)棧,用來保存正在執(zhí)行的表達式中的操作數(shù)

2、局部變量區(qū),用來保存方法中使用的變量,包括方法參數(shù),方法內(nèi)部聲明的變量,以及方法中使用到的對象的成員變量或類的成員變量(靜態(tài)變量),最后兩種變量會復(fù)制到局部變量區(qū),因此在多線程環(huán)境下,這種變量需要根據(jù)需要聲明為volatile類型

3、字節(jié)碼指令區(qū)

例如下面這段代碼

try{
  return expression;
}finally{
  do some work;
}

首先我們知道,finally語句是一定會執(zhí)行,但他們的執(zhí)行順序是怎么樣的呢?他們的執(zhí)行順序如下:

1、執(zhí)行:expression,計算該表達式,結(jié)果保存在操作數(shù)棧頂;

2、執(zhí)行:操作數(shù)棧頂值(expression的結(jié)果)復(fù)制到局部變量區(qū)作為返回值;

3、執(zhí)行:finally語句塊中的代碼;

4、執(zhí)行:將第2步復(fù)制到局部變量區(qū)的返回值又復(fù)制回操作數(shù)棧頂;

5、執(zhí)行:return指令,返回操作數(shù)棧頂?shù)闹担?/p>

我們可以看到,在第一步執(zhí)行完畢后,整個方法的返回值就已經(jīng)確定了,由于還要執(zhí)行finally代碼塊,因此程序會將返回值暫存在局部變量區(qū),騰出操作數(shù)棧用來執(zhí)行finally語句塊中代碼,等finally執(zhí)行完畢,再將暫存的返回值又復(fù)制回操作數(shù)棧頂。所以無論finally語句塊中執(zhí)行了什么操作,都無法影響返回值,所以試圖在finally語句塊中修改返回值是徒勞的。因此,finally語句塊設(shè)計出來的目的只是為了讓方法執(zhí)行一些重要的收尾工作,而不是用來計算返回值的。

這樣就能解釋Demo6的問題了

讓我們再來看以下 3 個例子。

Demo7

public class Test {
  public static void main(String[] args) {
    System.out.println("return value of getValue(): " + getValue());
  }
  @SuppressWarnings("finally")
  public static int getValue() {
    int i = 1;
    try {
      i = 4;
    } finally {
      i++;
      return i;
    }
  }
}

Demo7的執(zhí)行結(jié)果為:

return value of getValue(): 5

Demo8

public class Test {
  public static void main(String[] args) {
    System.out.println("return value of getValue(): " + getValue());
  }
  public static int getValue() {
    int i = 1;
    try {
      i = 4;
    } finally {
      i++;
    }
    return i;
  }
}

Demo8的執(zhí)行結(jié)果為:

return value of getValue(): 5

Demo9

public class Test {
  public static void main(String[] args) {
    System.out.println(test());
  }
  public static String test() {
    try {
      System.out.println("try block");
      return test1();
    } finally {
      System.out.println("finally block");
    }
  }
  public static String test1() {
    System.out.println("return statement");
    return "after return";
  }
}

Demo9的執(zhí)行結(jié)果為:

try block
return statement
finally block
after return

總結(jié):

1、finally 語句塊不一定會被執(zhí)行

2、finally 語句塊在 try 語句塊中的 return 語句之前執(zhí)行

3、finally 語句塊在 catch 語句塊中的 return 語句之前執(zhí)行

4、finally 語句塊中的 return 語句會覆蓋 try 塊中的 return 返回

5、試圖在 finally 語句塊中修改返回值不一定會被改變

相關(guān)文章

  • Spring中ClassPath指的是哪些地方

    Spring中ClassPath指的是哪些地方

    在Spring應(yīng)用中,ClassPath指的是應(yīng)用程序的類加載路徑,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-06-06
  • eclipse啟動出現(xiàn)“failed to load the jni shared library”問題解決

    eclipse啟動出現(xiàn)“failed to load the jni shared library”問題解決

    這篇文章主要介紹了eclipse啟動出現(xiàn)“failed to load the jni shared library”問題解決,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-11-11
  • spring boot實現(xiàn)文件上傳

    spring boot實現(xiàn)文件上傳

    這篇文章主要為大家詳細介紹了spring boot實現(xiàn)文件上傳,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-08-08
  • Java使用TCP實現(xiàn)數(shù)據(jù)傳輸實例詳解

    Java使用TCP實現(xiàn)數(shù)據(jù)傳輸實例詳解

    這篇文章主要介紹了Java使用TCP實現(xiàn)數(shù)據(jù)傳輸實例詳解的相關(guān)資料,需要的朋友可以參考下
    2017-06-06
  • Spring官網(wǎng)下載各版本jar包的方法

    Spring官網(wǎng)下載各版本jar包的方法

    這篇文章主要介紹了Spring官網(wǎng)下載各版本jar包的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2019-04-04
  • 利用Java實現(xiàn)網(wǎng)站聚合工具

    利用Java實現(xiàn)網(wǎng)站聚合工具

    互聯(lián)網(wǎng)上有數(shù)以萬億計的網(wǎng)站,每個網(wǎng)站大都具有一定的功能。搜索引擎雖然對互聯(lián)網(wǎng)上的部分網(wǎng)站建立了索引,但是其作為一個大而全的搜索系統(tǒng),無法很好的定位到一些特殊的需求。因此本文將介紹一個用java實現(xiàn)的網(wǎng)站數(shù)據(jù)聚合工具,需要的可以參考一下
    2022-01-01
  • MyBatis動態(tài)SQL中的trim標(biāo)簽的使用方法

    MyBatis動態(tài)SQL中的trim標(biāo)簽的使用方法

    這篇文章主要介紹了MyBatis動態(tài)SQL中的trim標(biāo)簽的使用方法,需要的朋友可以參考下
    2017-05-05
  • 出現(xiàn)java.lang.NoSuchMethodException異常的解決(靠譜)

    出現(xiàn)java.lang.NoSuchMethodException異常的解決(靠譜)

    這篇文章主要介紹了出現(xiàn)java.lang.NoSuchMethodException異常的解決方案(靠譜),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • Intellij IDEA 2018配置Java運行環(huán)境的方法步驟

    Intellij IDEA 2018配置Java運行環(huán)境的方法步驟

    這篇文章主要介紹了Intellij IDEA 2018配置Java運行環(huán)境的方法步驟,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-09-09
  • Maven jar包沖突的解決方案

    Maven jar包沖突的解決方案

    這篇文章主要介紹了Maven jar包沖突的解決方案,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-04-04

最新評論

志丹县| 兴国县| 左贡县| 澳门| 萨嘎县| 新野县| 江安县| 乌什县| 赤城县| 寿阳县| 丹东市| 阜新市| 于田县| 囊谦县| 黄石市| 金乡县| 张北县| 汕尾市| 凤山县| 浦东新区| 南雄市| 广元市| 乌拉特前旗| 城口县| 射洪县| 印江| 鲁甸县| 武川县| 临邑县| 兴文县| 东乌| 闽清县| 平江县| 昌图县| 章丘市| 德昌县| 玉环县| 和政县| 桐城市| 黔西| 博野县|