看了你就掌握---------JAVA中finally語句塊的詳解!!!!!
關於JAVA中finally語句塊的詳解
目錄
前言
相信同學們學習到面向物件的異常處理中應該會踩到finally語句塊這個坑中,本篇博文通過各種案例幫你如何避免踩坑,踩雷,讓你對異常處理的學習更加透徹,finally語句塊掌握的更加紮實!
一、finally語句塊的特點及應用場景
在進行異常處理時,finally語句塊也在異常的處理格式中,finally語句塊是整個異常處理的統一出口,不管是產生了異常還是未產生異常,那麼finally語句塊中的內容必然執行。
來一個小案例:
import java.lang.Exception;
public class Exception1 {
public static void main(String[] args){
int i = 10;
int j = 0;
try{
System.out.println("輸入的結果為" + i/j);
}catch (Exception e ){
System.out.println("動動你的腦筋,除數不能為0" );
return;
}finally {
System.out.println("finally語句執行了!");
}
}
}
執行結果:
動動你的腦筋,除數不能為0
finally語句執行了!
看完這段程式碼有人就有疑惑,為什麼我在catch語句塊中return了為什麼後面的程式碼還會執行?
因為我們在進行異常處理流程時,當catch語句塊執行到return的時候,我們需要做準備return的操作,雖然這個返回值沒有,但預設還是要把這個沒有返回值的東西返回(可能有點繞,慢慢理解),在這個準備的過程中,我們就把finally語句塊的內容執行了,執行完畢後,再return 結束掉這個方法。
二、finally語句塊在任何情況一定會執行嗎?
答案是:否!
第一種情況:JVM退出,finally不會執行。
import java.lang.Exception;
public class Exception2 {
public static void main(String[] args){
int i = 10;
int j = 0;
try{
System.out.println("輸入的結果為" + i/j);
}catch (Exception e ){
System.out.println("動動你的腦筋,除數不能為0")
System.exit(1);// 退出JVM
}finally {
System.out.println("finally語句執行了!");
}
}
執行結果:
動動你的腦筋,除數不能為0
這種情況下,我們發現finally語句塊並沒有執行。因為我們在catch語句塊中首先顯示了錯誤資訊,並退出了JAVA虛擬機器,導致程式碼執行到此處,整個程式就結束了。
第二種情況:異常處理前結束方法,finally不會執行。
這種情況是在進行異常處理前就return,結束了方法,那麼後面的所有程式碼都不會執行,finally語句塊也一定不會執行(編譯器也不會讓你寫return之後的程式碼)。
第三種情況:在異常處理前,產生了其他的異常,finally不會執行。
public class Exception3 {
public static void main(String[] args){
int i = 10;
int j = 0;
System.out.println(i/j);
try{
System.out.println("try..........");
}finally {
System.out.println("finally.........");
}
}
}
執行結果:
Exception in thread "main" java.lang.ArithmeticException: / by zero
at kkb.Exception3.main(Exception3.java:6)
這種情況是在處理異常前,產生了其他的異常,既出現異常,後面的程式碼不會執行,直接結束了方法。
三、finally和final的區別
有很多同學不知道finally和final是幹什麼的,就像方法的過載和重寫一樣,都是名字差不多,但是它們的應用的場景完全不同,完全沒有共同點。
finally:finally是一個語句塊,是屬於異常處理結構的成員之一,無論異常是否發生,finally語句塊的內容一定輸出,所以當我們需要編寫無論發生什麼都必須執行的程式碼時,就可以在finally語句塊中。
final:final是一個關鍵字,可以修飾類、變數和方法,被final修飾的類不可以被派生出新的子類。被final修飾的方法不能被重寫,不能修改方法中的內容。被fianl修飾的變數只能賦一次值,通常用fianl來修飾常量:public abstract final int +變數名。
四、finally常見踩坑面試題目
finally主要分為以下兩種題型,掌握了思想,那麼所有題目迎刃而解。
第一個案例:
class Person{ //建立一個Person類
int age; //屬性有age
}
public class Exception4 {
public static void main(String[] args){
Person p = p(); //呼叫p方法
System.out.println(p.age); //輸入age的值
}
public static Person p(){
Person p = new Person(); //建立Person物件
p.age = 0; //將預設值設為0
try{
p.age = 18;
return p;
}catch (Exception e){
p.age = 10;
return p;
}finally {
p.age = 20;
}
}
}
執行結果:
20
題解:
首先先分析流程 我們在try語句塊中將p.age設定為了18,然後返回這個物件,因為我們沒有設定年齡的限制,所以catch語句塊的內容一定不會執行。
當代碼執行進入try語句塊時,首先將p.age設定為18,然後進入return p語句,在執行這段程式碼時,我們可以理解為先複製了這個p的記憶體地址,然後進入finally語句塊中,將p.age設定為了20,然後再將這個p儲存的記憶體地址返回。因為在堆物件中,這個p.age被finally語句塊改變,所以在返回的p中包含的已被修改後的p.age的值。所以最終列印的結果為20;
重點:當返回的資料時引用資料型別時,返回的是該物件的記憶體地址!!!
第二個案例:
public class Exception5 {
public static void main(String[] args){
int code = i();
System.out.println(code);
}
public static int i(){
int i = 0;
try{
return i;
}finally {
i = 20;
}
}
}
執行結果:
0
題解:
首先分析流程,在i()方法中我們先定義了個基本資料型別的變數i =0,在try語句塊中返回了這個i,在finally語句塊中修改了i的值。大家可能會認為,在try語句的return返回之前應該先執行finally語句塊,修改完畢後再返回嗎。最後輸出結果應該是20才對。
流程:我們在return語句返回這個i之前,首先先把i的值(資料0)複製一份,然後進入finally語句塊,我們把i修改為20,然後再執行return,那麼return返回的仍然是這個複製好的資料。所以輸出是0;
總結兩道案例:
這兩道案例一個返回的基本資料型別,一個是返回的引用資料型別。
區別:
引用資料型別儲存的資料在堆中,執行完finally語句後,返回的是這個物件的記憶體地址複製,記憶體地址再指向物件,如果物件中的資料被改變,那麼記憶體地址指向的這個物件也會發生改變。
區域性變數中基本資料型別的資料儲存在棧中,執行完finally語句後,返回的是這個資料本身的複製,如果資料被改變,那麼返回內容則不變。
總結
以上就是今天要講的內容,本文講解了finally語句塊的執行流程,通過一個個案例來告訴同學們在各種場景下的finally語句塊該如何執行的問題,希望能幫助到在此知識點上模糊的同學。覺得有幫助的同學來個三連哦!