finally塊的問題(finally block does not complete normal

當finall塊中包含return語句時,Eclipse會給出警告「finally block does not complete normally」,緣由分析以下:java

一、無論try塊、catch塊中是否有return語句,finally塊都會執行。
二、finally塊中的return語句會覆蓋前面的return語句(try塊、catch塊中的return語句),因此若是finally塊中有return語句,Eclipse編譯器會報警告「finally block does not complete normally」。web

三、若是finally塊中包含了return語句,即便前面的catch塊從新拋出了異常,則調用該方法的語句也不會得到catch塊從新拋出的異常,而是會獲得finally塊的返回值,而且不會捕獲異常。函數

 

結論,測試

finally 內部使用 return 語句是一種很很差的習慣,若是try中還有return語句,它會覆蓋了try 區域中 return 語句的返回值,程序的可讀性差spa


面對上述狀況,其實更合理的作法是,既不在 try block 內部中使用 return 語句,也不在 finally 內部使用 return 語句,而應該在 finally 語句以後使用 return 來表示函數的結束和返回code

 

 

 

結論:
一、無論有木有出現異常,finally塊中代碼都會執行;
二、當try和catch中有return時,finally仍然會執行;
三、finally是在return後面的表達式運算後執行的(此時並無返回運算後的值,而是先把要返回的值保存起來,管finally中的代碼怎麼樣,返回的值都不會改變,任然是以前保存的值),因此函數返回值是在finally執行前肯定的;
四、finally中最好不要包含return,不然程序會提早退出,返回值不是try或catch中保存的返回值。
舉例:
狀況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;}
          程序執行catch塊中return以前(包括return語句中的表達式運算)代碼;
          再執行finally塊,由於finally塊中有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。
orm

 

下面是個測試程序public class FinallyTest  
{
	public static void main(String[] args) {
		 
		System.out.println(new FinallyTest().test());;
	}

	static int test()
	{
		int x = 1;
		try
		{
			x++;
			return x;
		}
		finally
		{
			++x;
		}
	}
}結果是2。

分析:	在try語句中,在執行return語句時,要返回的結果已經準備好了,就在此時,程序轉到finally執行了。
在轉去以前,try中先把要返回的結果存放到不一樣於x的局部變量中去,執行完finally以後,在從中取出返回結果,
所以,即便finally中對變量x進行了改變,可是不會影響返回結果。
它應該使用棧保存返回值。

 

public class Ex1 {

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

    public static int getResult(){
        int a =100;
        
        try{
            return a+10; //注意,java的基礎數據類型是值傳遞,這裏的返回值已經和上面的a沒有關係了
        }catch(Exception e){ip

            e.printStackTrace();  
        }finally{
            return a;    //最後再把值重定向到a(至關於將try中的返回值覆蓋掉),因此輸出仍是100
        }
    }
}資源

複製代碼

 再看一個例子:get

 

複製代碼

public class Ex1 {

    public static void main(String[] args) {
        try{
        System.out.println(Ex1.getResult());
        }catch(Exception e){
            e.printStackTrace();
            System.out.println("截獲異常catch");
        }finally{
            System.out.println("異常處理finally");
        }
    }

    public static int getResult() throws Exception{
        int a =100;
        
        try{
            
            a=a+10; 
            throw new RuntimeException();
        }catch(Exception e){
            System.out.println("截獲異常並從新拋出異常");
            throw new Exception();            
        }finally{
            return a;
        }
    }
}

複製代碼

輸出以下:

截獲異常並從新拋出異常
110
異常處理finally
關鍵的「截獲異常catch」卻沒有執行!!!

緣由是在getResult()的finally中return一個值,等同於告訴編譯器該方法沒有異常,但實際上異常是有的,這樣的結果是該方法的調用者卻捕獲不到異常,相對於異常被無故的被吃掉了,隱藏殺機啊!!

結論:不要再finally中試圖return一個值,這樣可能會致使一些意想不到的邏輯錯誤,finally就是用來釋放資源的!!

相關文章
相關標籤/搜索