java中 try catch finally和return聯合使用時,代碼執行順序的小細節

 

代碼1測試css

	public static void main(String[] args) {
		aa();
	}

	static int aa() {
		try {
			int a=4/0;
		} catch (Exception e) {
			e.printStackTrace();
			return 1;
		}finally{
			System.out.println("finally");
//			return 2; return寫在這裏不規範,不是錯誤,但有感嘆號
		}
return 2; }

  

輸出結果以下:java

  java.lang.ArithmeticException: / by zero
    at com.hcss.cn.Aa1fa.aa(Ja.java:120)
    at com.hcss.cn.Aa1fa.main(Ja.java:115)
  finally算法

分析:雖然try中出現了運行異常java.lang.ArithmeticException,被catch捕獲到,無論程序是正常運行,仍是拋異常,以前都要先調用finally(這裏想說下屢次執行程序時控制檯輸出信息順序會變,是由於e.printStatckTrace和System.out是兩個資源,並行執行,但代碼2我都用成System.out,屢次輸出也會偶爾出現亂序,沒搞明白,先無論這個小問題了),finally正確使用應該是釋放資源,若是finally用了return,這是不規範的寫法。express

 稍微變形的代碼2測試(catch的異常類變了)數據結構

public static void main(String[] args) {
        System.out.println(aa());
    }

    static int aa() {
        try {
            int a=4/0;
        } catch (Error e) {
            System.out.println("catch...");
            return 1;
        }finally{
            System.out.println("finally...");
        }

      //執行完finally,由於沒有catch住ArithmeticException異常,致使異常向上層main方法拋出,下邊兩行system.out沒有輸出
      System.out.println("finally1...");
      System.out.println("finally2...");多線程

return 2;

    }

輸出結果以下:學習

  finally...
  Exception in thread "main" java.lang.ArithmeticException: / by zero
    at com.hcss.cn.Aa1fa.aa(Ja.java:120)
    at com.hcss.cn.Aa1fa.main(Ja.java:115)測試

分析:spa

  執行完finally,由於沒有catch住ArithmeticException異常,致使異常向上層main方法拋出,下邊兩行system.out沒有輸出。.net

 

再變形代碼3測試(return寫在了finally裏)

public static void main(String[] args) {
        System.out.println(aa());
    }

    static int aa() {
        try {
            int a=4/0;
        } catch (Error e) {
            System.out.println("catch...");
            return 1;
        }finally{
            System.out.println("finally...");
            return 2; //return寫在這裏不規範,有感嘆號
        }
    }
輸出結果以下:

  finally...
  2

分析
  finally用了return,這是不規範的寫法,不該該這麼使用,finally中的return使得aa方法丟失了要拋出的異常,至關於aa方法沒有向main方法拋出異常,而是隻返回一個2。

然後,從網上找到一篇文章,看完又學到一點原理性的小知識(重點是return返回的是一個快照值):

一些準備知識:    首先爲了說明白java中finally與return的執行順序是怎樣的這個問題,咱們須要作一點準備工做。    java方法是在棧幀中執行,棧幀是線程私有棧的單位,執行方法的線程會爲每個方法分配一小塊棧空間來做爲該方法執行時的內存空間,棧幀分爲三個區域:    1. 操做數棧,用來保存正在執行的表達式中的操做數,數據結構中學習過基於棧的多項式求值算法,操做數棧的做用和這個同樣    2. 局部變量區,用來保存方法中使用的變量,包括方法參數,方法內部聲明的變量,以及方法中使用到的對象的成員變量或類的成員變量(靜態變量),最後兩種變量會複製到局部變量區,所以在多線程          環境下,這種變量須要根據須要聲明爲volatile類型    3. 字節碼指令區,這個不用解釋了,就是方法中的代碼翻譯成的指令return語句:    準備知識講完了,在本節中咱們講解方法中沒有finally語句塊的狀況下return語句的執行方式。如今咱們先看看return語句,return語句的格式以下:    return [expression];    其中expression(表達式)是可選的,由於有些方法沒有返回值,因此return後面也就沒有表達式,或者能夠看作是空的表達式。    咱們知道return語句的做用能夠結束方法並返回一個值,那麼他返回的是哪裏的值呢?返回的是return指令執行的時刻,操做數棧頂的值,無論expression是一個怎樣的表達式,究竟作了些什麼工做,對於return指令來講都不重要,他只負責把操做數棧頂的值返回。    而return expression是分紅兩部分執行的:    執行:expression;    執行:return指令;    例如:return x+y;    這句代碼先執行x+y,再執行return;首先執行將x以及y從局部變量區複製到操做數棧頂的指令,而後執行加法指令,這個時候結果x+y的值會保存在操做數棧的棧頂,最後執行return指令,返回操做數棧頂的值。    對於return x;先執行x,x也是一個表達式,這個表達式只有一個操做數,會執行將變量x從局部變量區複製到操做數棧頂的指令,而後執行return,返回操做數棧頂的值。所以return x實際返回的是return指令執行時,x在操做數棧頂的一個快照或者叫副本,而不是x這個值。finally語句塊:    若是方法中有finally語句塊,那麼return語句又是如何執行的呢?    例以下面這段代碼:    try{    return expression;  }finally{    do some work;  }  首先咱們知道,finally語句是必定會執行,但他們的執行順序是怎麼樣的呢?他們的執行順序以下:    一、執行:expression,計算該表達式,結果保存在操做數棧頂;    二、執行:操做數棧頂值(expression的結果)複製到局部變量區做爲返回值;    三、執行:finally語句塊中的代碼;    四、執行:將第2步複製到局部變量區的返回值又複製回操做數棧頂;    五、執行:return指令,返回操做數棧頂的值;    咱們能夠看到,在第一步執行完畢後,整個方法的返回值就已經肯定了,因爲還要執行finally代碼塊,所以程序會將返回值暫存在局部變量區,騰出操做數棧用來執行finally語句塊中代碼,等finally執行完畢,再將暫存的返回值又複製回操做數棧頂。因此不管finally語句塊中執行了什麼操做,都沒法影響返回值,因此試圖在finally語句塊中修改返回值是徒勞的。所以,finally語句塊設計出來的目的只是爲了讓方法執行一些重要的收尾工做,而不是用來計算返回值的。若是還有不懂的話能夠看看示例代碼public class FinallyDemo {         public int testMethod(String _int,String _className){                 int x = 1;                 try{            Integer.valueOf(_int);            Class.forName(_className);            //若是上面兩句代碼沒有發生異常,對於return x這句代碼,程序會先計算表達式x            //即將x從局部變量區複製到操做數棧頂,結果就是操做數棧頂的值,也就是x的值,爲1            //而後將操做數棧頂的值複製到局部變量區(假設這個複製到局部變量區的值叫returnvalue),再執行finally代碼塊,在finally代碼塊            //中,x的值被修改成3(即局部變量區中的x值),finally執行完,程序又將returnvalue複製到操做數棧頂,而後執行return指令,返回            //操做數棧頂的值,最終返回值是1            return x;        }catch(ClassNotFoundException e){            //一樣發生了ClassNotFoundException,x的值被修改爲2            //所以在catch中的return x語句中定義了返回值大小爲2,因此最終返回的是2            x = 2;            return x;        }finally{            //這句代碼必定會執行的,這裏的代碼執行結束後纔會結束方法並返回值,所以在finally語句修改x不會影響返回值,由於返回值在return 後面的            //表達式執行完就已經肯定了,他是x的快照,而不是x            x = 3;        }    }         public static void main(String [] args){        try{            FinallyDemo demo = new FinallyDemo();            int i_1 = demo.testMethod("123123", "expert.in.java.lang.CalendarDemo");            System.out.println(i_1);//結果爲1            int i_2 = demo.testMethod("123123", "com.edu.cn.qj.MyClass");            System.out.println(i_2);//結果爲2            int i_3 = demo.testMethod("dsadf", "expert.in.java.lang.CalendarDemo");            System.out.println(i_3);//沒有返回值,會拋出異常        }finally{                     }    }}--------------------- 做者:qj19842011 來源:CSDN 原文:https://blog.csdn.net/qj19842011/article/details/45675057 版權聲明:本文爲博主原創文章,轉載請附上博文連接!

相關文章
相關標籤/搜索