搜尋
首頁Javajava教程Java中try與finally以及return語句的執行順序

Java中try與finally以及return語句的執行順序

Aug 23, 2017 am 10:19 AM
finallyjavareturn

這篇文章主要介紹了關於Java中try finally return語句的執行順序淺析,需要的朋友可以參考下

問題分析

finally語句區塊一定會執行嗎?

可能很多人第一反應是肯定要執行的,但仔細一想,如果一定會執行的話 也就不會這麼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的執行結果如下:


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)

另外,如果去掉上例中的註釋,執行結果則是:


#
return value of test(): 0

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

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的執行結果如下:


#
try block

finally語句區塊還是沒有執行,為什麼呢?因為我們在try語句區塊中執行了System.exit(0)語句,終止了Java虛擬機器的運行,雖然一般情況下我們不會這麼幹。還有情況是當一個執行緒在執行try語句區塊或catch語句區塊時被打斷(interrupted)或被終止(killed),與其對應的finally語句區塊可能不會執行。還有更極端的情況,就是在執行緒執行 try 語句區塊或 catch 語句區塊時,突然當機或斷電,finally 語句區塊肯定不會執行了。

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的執行結果為:


try block
finally block

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

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的執行結果為:


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

Demo4說明了finally 語句區塊在catch 語句區塊中的return 語句之前執行。

從上面的Demo3和Demo4,我們可以看出,其實finally語句區塊時在try或catch中的return語句之前執行的,更加一般的說法是,finally語句區塊應該是在控制轉移語句之前執行,控制轉移語句除了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的執行結果為:

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的執行結果為:


return value of getValue(): 1

利用我們上面分析的結論:finally 語句區塊是在try 或catch 中的return 語句之前執行的。 由此,可以輕鬆的理解Demo5 的執行結果是 1。因為finally 中的return 1;語句要在try 中的return 0;語句之前執行,那麼finally 中的return 1;語句執行後,把程式的控制權轉交給了它的呼叫者main()函數,並且返回值為1。那為什麼Demo6 的回傳值不是 2,而是 1 呢?依照Demo5 的分析邏輯,finally 中的 i++;語句應該在 try 中的 return i;之前執行啊? i 的初始值為 1,那麼執行 i++;之後為 2,再執行 return i;那不就應該是 2 嗎?怎麼變成 1 了呢?

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

Java方法是在堆疊幀中執行,堆疊幀是線程私有堆疊的單位,執行方法的執行緒會為每一個方法分配一小塊空間來作為該方法執行時的記憶體空間,堆疊幀分為三個區域:

1、操作數棧,用來保存正在執行的表達式中的操作數

2、局部變數區,用來保存方法中使用的變量,包括方法參數,方法內部聲明的變量,以及方法中使用到的對象的成員變量或類別的成員變量(靜態變量),最後兩個變量會複製到局部變量區,因此在多線程環境下,這種變數需要根據需要宣告為volatile類型

3、字節碼指令區

例如下面這段程式碼


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

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

1、執行:expression,計算該表達式,結果保存在操作數棧頂;

2、執行:操作數棧頂值(expression的結果)複製到局部變數區作為返回值;

3、执行:finally语句块中的代码;

4、执行:将第2步复制到局部变量区的返回值又复制回操作数栈顶;

5、执行:return指令,返回操作数栈顶的值;

我们可以看到,在第一步执行完毕后,整个方法的返回值就已经确定了,由于还要执行finally代码块,因此程序会将返回值暂存在局部变量区,腾出操作数栈用来执行finally语句块中代码,等finally执行完毕,再将暂存的返回值又复制回操作数栈顶。所以无论finally语句块中执行了什么操作,都无法影响返回值,所以试图在finally语句块中修改返回值是徒劳的。因此,finally语句块设计出来的目的只是为了让方法执行一些重要的收尾工作,而不是用来计算返回值的。

这样就能解释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的执行结果为:


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的执行结果为:


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的执行结果为:


try block
return statement
finally block
after return

总结:

1、finally 语句块不一定会被执行

2、finally 语句块在 try 语句块中的 return 语句之前执行

3、finally 语句块在 catch 语句块中的 return 语句之前执行

4、finally 语句块中的 return 语句会覆盖 try 块中的 return 返回

5、试图在 finally 语句块中修改返回值不一定会被改变

以上是Java中try與finally以及return語句的執行順序的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
在平台獨立性的平台獨立性上使用字節碼優於本機代碼的優點是什麼?在平台獨立性的平台獨立性上使用字節碼優於本機代碼的優點是什麼?Apr 30, 2025 am 12:24 AM

ByteCodeachievesPlatFormIndenceByByByByByByExecutedBoviratualMachine(VM),允許CodetorunonanyplatformwithTheApprepreprepvm.Forexample,Javabytecodecodecodecodecanrunonanydevicewithajvm

Java真的100%獨立於平台嗎?為什麼或為什麼不呢?Java真的100%獨立於平台嗎?為什麼或為什麼不呢?Apr 30, 2025 am 12:18 AM

Java不能做到100%的平台獨立性,但其平台獨立性通過JVM和字節碼實現,確保代碼在不同平台上運行。具體實現包括:1.編譯成字節碼;2.JVM的解釋執行;3.標準庫的一致性。然而,JVM實現差異、操作系統和硬件差異以及第三方庫的兼容性可能影響其平台獨立性。

Java的平台獨立性如何支持代碼可維護性?Java的平台獨立性如何支持代碼可維護性?Apr 30, 2025 am 12:15 AM

Java通過“一次編寫,到處運行”實現平台獨立性,提升代碼可維護性:1.代碼重用性高,減少重複開發;2.維護成本低,只需一處修改;3.團隊協作效率高,方便知識共享。

為新平台創建JVM面臨哪些挑戰?為新平台創建JVM面臨哪些挑戰?Apr 30, 2025 am 12:15 AM

在新平台上創建JVM面臨的主要挑戰包括硬件兼容性、操作系統兼容性和性能優化。 1.硬件兼容性:需要確保JVM能正確使用新平台的處理器指令集,如RISC-V。 2.操作系統兼容性:JVM需正確調用新平台的系統API,如Linux。 3.性能優化:需進行性能測試和調優,調整垃圾回收策略以適應新平台的內存特性。

Javafx庫如何試圖解決GUI開發中的平台不一致?Javafx庫如何試圖解決GUI開發中的平台不一致?Apr 30, 2025 am 12:01 AM

javafxeffectife addressemanddressEndressencissencies uningusement insuplatform-agnosticsCenegraphandCsSsStyling.1)itabstractsplactsplatsplatsplatsplatsplatformsthroughascenegraph,確保consistentertrenderingrenderingrenderingacrosswindows,macoswindwind,Macos,MacOs.2)

說明JVM如何充當Java代碼和基礎操作系統之間的中介。說明JVM如何充當Java代碼和基礎操作系統之間的中介。Apr 29, 2025 am 12:23 AM

JVM的工作原理是將Java代碼轉換為機器碼並管理資源。 1)類加載:加載.class文件到內存。 2)運行時數據區:管理內存區域。 3)執行引擎:解釋或編譯執行字節碼。 4)本地方法接口:通過JNI與操作系統交互。

解釋Java虛擬機(JVM)在Java平台獨立性中的作用。解釋Java虛擬機(JVM)在Java平台獨立性中的作用。Apr 29, 2025 am 12:21 AM

JVM使Java實現跨平台運行。 1)JVM加載、驗證和執行字節碼。 2)JVM的工作包括類加載、字節碼驗證、解釋執行和內存管理。 3)JVM支持高級功能如動態類加載和反射。

您將採取哪些步驟來確保Java應用程序在不同的操作系統上正確運行?您將採取哪些步驟來確保Java應用程序在不同的操作系統上正確運行?Apr 29, 2025 am 12:11 AM

Java應用可通過以下步驟在不同操作系統上運行:1)使用File或Paths類處理文件路徑;2)通過System.getenv()設置和獲取環境變量;3)利用Maven或Gradle管理依賴並測試。 Java的跨平台能力依賴於JVM的抽象層,但仍需手動處理某些操作系統特定的功能。

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

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

AI Clothes Remover

AI Clothes Remover

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

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

強大的PHP整合開發環境

EditPlus 中文破解版

EditPlus 中文破解版

體積小,語法高亮,不支援程式碼提示功能

PhpStorm Mac 版本

PhpStorm Mac 版本

最新(2018.2.1 )專業的PHP整合開發工具

Atom編輯器mac版下載

Atom編輯器mac版下載

最受歡迎的的開源編輯器

WebStorm Mac版

WebStorm Mac版

好用的JavaScript開發工具