1. 程式人生 > >JAVA try catch finally return 執行順序

JAVA try catch finally return 執行順序

JAVA try catch finally return 執行順序

參考:https://www.cnblogs.com/superFish2016/p/6687549.html

一、結論

1、不管有沒有出現異常,finally塊中程式碼都會執行;
2、當try和catch中有return時,finally仍然會執行;
3、如果try、catch中有return語句,finally是在return後面的表示式運算後執行的。

  • 如果是基本資料型別、靜態變數。(此時並沒有返回finally中運算後的值,而是先把要返回的值儲存起來,不管finally中的程式碼怎麼樣,返回的值都不會改變,仍然是之前儲存的值),所以函式返回值是在finally執行前確定的;
  • 如果是引用資料型別,那麼在finally中修改除包裝型別,會對try、catch中返回的變數有影響。
    原因:JAVA基本資料型別、物件的引用以及方法引數存放在棧中,引用物件本身放在堆中。
    • 1 暫存器:最快的儲存區,由編譯器根據需求進行分配,我們在程式中無法控制。
    • 2 棧:存放基本型別的變數資料和物件的引用以及方法引數,但物件本身不存放在棧中,而是存放在堆(new出來的物件)或者常量池中(字串常量物件存放在常量池中。)
    • 3 堆:存放所有new出來的物件。
    • 4 靜態域:存放靜態成員(static定義的)
    • 5 常量池:存放字串常量和基本型別常量(public static final)。

4、儘量不要在finally中使用return語句,如果使用的話,會忽略try、catch中的返回語句,也會忽略try、catch中的異常,遮蔽了錯誤的發生。
5、finally中避免再次丟擲異常,一旦finally中發生異常,程式碼執行將會丟擲finally中的異常資訊,try、catch中的異常將被忽略

所以在實際專案中,finally常常是用來關閉流或者資料庫資源的,並不額外做其他操作。

二、return

return語句用來結束迴圈(函式),或返回一個函式的值。
1 return, 如果什麼都不接的話,其實就是void型別函式的返回,返回後不再執行return後面的語句
如果函式執行成功返回0,不成功返回非0,一般情況下非0值常用-1來表示。
2 return 0:一般用在主函式結束時,表示程式正常終止,即告訴系統程式正常。
3 return -1::表示返回一個代數值,一般用在子函式結尾。表示程式異常終止,即告訴系統程式異常
4 return 1:與return -1相同。

三、程式碼例項

3.1基本資料型別和static型別

1、沒有異常、沒有return
	public static int testBasic1() {// 10
		int i = 1;
		try {
			i++;
			System.out.println("1try block, i = " + i);// 1try block, i = 2
		} catch (Exception e) {
			i++;
			System.out.println("1catch block i = " + i);// 沒輸出
		} finally {
			i = 10;
			System.out.println("1finally block i = " + i);// 1finally block i = 10
		}
		return i;// 10
	}
2、沒有異常、有return

執行順序:try return有一個返回值 執行finally

  • 在轉去之前,try中先把要返回的結果存放到不同於i的區域性變數中去,執行完finally之後,在從中取出返回結果,
  • 因此,即使finally中對變數i進行了改變,但是不會影響返回結果。
  • 它應該使用棧儲存返回值。
	public static int testBasic2() {//不進入catch 返回的是2
		int i = 1;
		try {
			i++;
			System.out.println("2try block, i = " + i);//2try block, i = 2
			return i;
		} catch (Exception e) {
			i++;
			System.out.println("2catch block i = " + i);//沒輸出
			return i;
		} finally {
			i = 10;
			System.out.println("2finally block i = " + i);//2 finally block i = 10			
			// return i; 有警告
		}
	}
  • 程式碼順序執行從try到finally,由於finally是無論如何都會執行的,所以try裡的語句並不會直接返回。在try語句的return塊中,return返回的引用變數並不是try語句外定義的引用變數i,而是系統重新定義了一個區域性引用i’,這個引用指向了引用i對應的值,也就是2,即使在finally語句中把引用i指向了值10,因為return返回的引用已經不是i,而是i’,所以引用i的值和try語句中的返回值無關了。
3、有異常、有return

執行順序:try-異常(try中異常後的不執行)-catch-- return有一個返回值 執行finally

  • 在轉去之前,catch中先把要返回的結果存放到不同於i的區域性變數中去,執行完finally之後,在從中取出返回結果,
  • 因此,即使finally中對變數i進行了改變,但是不會影響返回結果。
  • 它應該使用棧儲存返回值。
	public static int testBasic3() {//進入catch 返回的是3
		int i = 1;
		try {
			i++;
			int j = 1/0;//丟擲異常 算術運算異常
			System.out.println("3try block, i = " + i);//不執行
			return i;
		} catch (Exception e) {
			i++;
			System.out.println("3catch block i = " + i);//輸出 3catch block i = 3
			return i;
		} finally {
			i = 10;
			System.out.println("3finally block i = " + i);//3finally block i = 10			
			// return i; //有警告
		}
	}
4、finally中有return
	public static int testBasic4() {//沒異常不進入catch,有異常進入catch 兩種情況返回的都是finally的10
		int i = 1;
		try {
			i++;
//			int j = 1/0;//丟擲異常 算術運算異常
			System.out.println("4try block, i = " + i);//不丟擲異常有輸出4try block, i = 2 //丟擲異常沒輸出
			return i;
		} catch (Exception e) {
			i++;
			System.out.println("4catch block i = " + i);//不丟擲異常沒輸出 //丟擲異常 有輸出4catch block i = 3 
			return i;
		} finally {
			i = 10;
			System.out.println("4finally block i = " + i);//finally block i = 10			
			return i; //有警告 finally中不要有返回值
		}
	}
5、finally中有異常
	public static  int testBasic5(){//finally中有異常 控制檯報錯 Exception in thread "main" java.lang.ArithmeticException: / by zero
        int i = 1; 
        try{
            i++;
            Integer.parseInt(null);
            System.out.println("5try block, i = "+i);
            return i;
        }catch(Exception e){
            String.valueOf(null);
            System.out.println("5catch block i = "+i);
            return i;
        }finally{
            i = 10;
            int m = i / 0;//Exception in thread "main" java.lang.ArithmeticException: / by zero
            System.out.println("5finally block i = "+i);
        }
}

3.2引用資料型別

1、沒有異常、finally無return。引用資料型別
	public static  List<Object> testWrap(){;//返回[try, finally]
        List<Object> list = new ArrayList<>();
        try{
            list.add("try");
            System.out.println("try block");//try block
            return list;
        }catch(Exception e){
            list.add("catch");
            System.out.println("catch block");
            return list;
        }finally{
            list.add("finally");
            System.out.println("finally block ");//finally block 
        }
	}
  • 可以看到,finally裡對list集合的操作生效了,這是為什麼呢。我們知道基本型別在棧中儲存,而對於非基本型別是儲存在堆中的,返回的是堆中的地址,因此內容被改變了。
2、有異常、finally無return。引用資料型別
	public static List<Object> testWrap2() {// 返回[try, catch, finally]

		List<Object> list = new ArrayList<>();
		try {
			list.add("try");
			int i = 1/0;
			System.out.println("try block");// 不輸出
			return list;
		} catch (Exception e) {
			list.add("catch");
			System.out.println("catch block");//輸出 catch block
			return list;
		} finally {
			list.add("finally");
			System.out.println("finally block ");// finally block
		}
	}
  • 可以看到,finally裡對list集合的操作生效了,這是為什麼呢。我們知道基本型別在棧中儲存,而對於非基本型別是儲存在堆中的,返回的是堆中的地址,因此內容被改變了。

總結

  • 舉例:
  • 情況1:try{} catch(){}finally{} return;
    • 顯然程式按順序執行。
  • 情況2:try{ return; }catch(){} finally{} return;
    • 程式執行try塊中return之前(包括return語句中的表示式運算)程式碼;
    • 再執行finally塊,最後執行try中return;
    • finally塊之後的語句return,因為程式在try中已經return所以不再執行。
  • 情況3:try{ } catch(){return;} finally{} return;
    • 程式先執行try,如果遇到異常執行catch塊,
    • 有異常:則執行catch中return之前(包括return語句中的表示式運算)程式碼,
      再執行finally語句中全部程式碼,
      最後執行catch塊中return. finally之後也就是4處的程式碼不再執行。
    • 無異常:執行完try再finally再return.
  • 情況4:try{ return; }catch(){} finally{return;}
    • 程式執行try塊中return之前(包括return語句中的表示式運算)程式碼;
      再執行finally塊,因為finally塊中有return所以提前退出。
  • 情況5:try{} catch(){return;}finally{return;}
    • 沒有異常:程式先執行try,然後執行finally,然後return;
    • 有異常:程式執行catch塊中return之前(包括return語句中的表示式運算)程式碼;
      再執行finally塊,因為finally塊中有return所以提前退出(不執行catch中的return)。
  • 情況6:try{ return;}catch(){return;} finally{return;}
    • 程式執行try塊中return之前(包括return語句中的表示式運算)程式碼;
    • 有異常:執行catch塊中return之前(包括return語句中的表示式運算)程式碼;
      則再執行finally塊,因為finally塊中有return所以提前退出。
    • 無異常:則再執行finally塊,因為finally塊中有return所以提前退出。

最終結論:

任何執行try 或者catch中的return語句之前,都會先執行finally語句,如果finally存在的話。
如果finally中有return語句,那麼程式就return了,所以finally中的return是一定會被return的,
編譯器把finally中的return實現為一個warning。