面試官問道:Java中的finally一定會被執行嗎?你怎麼回答?

推薦閱讀:阿里P8架構師談:工作1-5年的Java工程師,怎樣提高核心競爭力

                  阿里架構師直言:“沒有實戰都是紙上談兵”!Redis實戰PDF分享

                  奮發圖強半年多,終於四面阿里如願拿到心儀offer定級P7

一、前言

因爲這次面試有問到一些同學finally的問題,發現自己這塊好像有點記不太清楚了,有的點可能還給人家說錯了,一度弄得場面有些尷尬。所以說這篇文章深入研究一下finally的執行情況和返回值的情況。

二、finally一定會執行嗎?

先給答案:肯定不是。

我們可以看兩種情況:

1.在執行try塊之前直接return,我們發現finally塊是不會執行的

 

public class TryCatchTest {

  private static int total() {
    int i = 11;
    if (i == 11) {
      return i;
    }
    try {
      System.out.println("執行try");
    } finally {
      System.out.println("執行finally");
    }
    return 0;
  }

  public static void main(String[] args) {
    System.out.println("執行main:" + total());
  }
}

 


 

輸出結果:
執行main:11
複製代碼

2.在執行try塊之前製造一個錯誤,直接爆紅

 

public class TryCatchTest {

  private static int total() {
    return 1 / 0;
    try {
      System.out.println("執行try");
    } finally {
      System.out.println("執行finally");
    }
    return 0;
  }

  public static void main(String[] args) {
    System.out.println("執行main:" + total());
  }
}

綜上我們看出,如果程序連try塊都執行不到,那麼finally塊自然就不會執行到了

不過這裏有的同學就會問:如果執行了try塊,finally塊一定會執行嗎?有的同學答案就是一定會,其實非然,看看下面的例子吧:

public class TryCatchTest {

  private static int total() {
    try {
      System.out.println("執行try");
      System.exit(0);
    } catch (Exception e) {
      System.out.println("執行catch");
    } finally {
      System.out.println("執行finally");
    }
    return 0;
  }

  public static void main(String[] args) {
    System.out.println("執行main:" + total());
  }
}

 

輸出結果:
執行try

我們在執行try塊之中退出jvm,就沒事了,都不執行了。當然這個情況是比較極端的,記住就行,沒事不要亂整這個。最後總結一下:不管是給try塊中造了個異常,還是在try塊中進行return,我們發現finally塊還是會執行的。因爲異常處理設計初衷就是讓finally塊始終執行。這個總結在finally的執行時機得到證明。

三、finally執行時機探討

首先看常規情況:

public class TryCatchTest {

  private static int total() {
    try {
      System.out.println("執行try");
      return 11;
    } finally {
      System.out.println("執行finally");
    }
  }

  public static void main(String[] args) {
    System.out.println("執行main:" + total());
  }
}

 

輸出結果:
執行try
執行finally
執行main:11

分析一下,不難得出在這個例子中finally塊執行在try塊的return之前。我們給try塊中造一個異常:

public class TryCatchTest {

  private static int total() {
    try {
      System.out.println("執行try");
      return 1 / 0;
    } catch (Exception e) {
      System.out.println("執行catch");
      return 11;
    } finally {
      System.out.println("執行finally");
    }
  }

  public static void main(String[] args) {
    System.out.println("執行main:" + total());
  }
}

 

輸出結果:
執行try
執行catch
執行finally
執行main:11

同樣的,finally執行在catch塊return的執行前

四、finally塊中的返回值

 

1.finally塊不含返回值,但是做改變變量值的操作

看一個例子:

public class TryCatchTest {

  private static int total() {
    int i = 0;
    try {
      System.out.println("執行try:" + i);
      return i;
    } finally {
      ++i;
      System.out.println("執行finally:" + i);
    }
  }

  public static void main(String[] args) {
    System.out.println("執行main:" + total());
  }
}

 

輸出結果:
執行try:0
執行finally:1
執行main:0

如果看完前面分析,會發現跟想象的不太一樣。我們經過前面的分析,finally塊的執行時機應該是return之前,那理論上我們應該先++i使得i等於1,在執行return i; 自然會返回1。

可是結果卻返回了0,這是因爲Java程序會把try或者catch塊中的返回值保留,也就是暫時的確認了返回值,然後再去執行finally代碼塊中的語句。等到finally代碼塊執行完畢後,如果finally塊中沒有返回值的話,就把之前保留的返回值返回出去。

2.finally中含有返回值

示例1:

public class TryCatchTest {

  private static int total() {
    try {
      System.out.println("執行try");
      return 1;
    } finally {
      System.out.println("執行finally");
      return 2;
    }
  }

  public static void main(String[] args) {
    System.out.println("執行main:" + total());
  }
}

 

輸出結果:
執行try
執行finally
執行main:2


示例2:

public class TryCatchTest {

  private static int total() {
    int i = 1;
    try {
      System.out.println("執行try:" + i);
      return i;
    } finally {
      ++i;
      System.out.println("執行finally:" + i);
      return i;
    }
  }

  public static void main(String[] args) {
    System.out.println("執行main:" + total());
  }
}

 

輸出結果:
執行try:1
執行finally:2
執行main:2


示例3:

public class TryCatchTest {

  private static int total() {
    int i = 1;
    try {
      System.out.println("執行try:" + i);
    } finally {
      ++i;
      System.out.println("執行finally:" + i);
    }
    return i;
  }

  public static void main(String[] args) {
    System.out.println("執行main:" + total());
  }
}

 

執行結果:
執行try:1
執行finally:2
執行main:2

這三個示例都說明了一點,在分析含有finally塊的方法返回值時,要對於return出現的地方進行具體分析。在finally塊中進行return操作的話,則方法整體的返回值就是finally塊中的return返回值。如果在finally塊之後的方法內return,則return的值就是進行完上面的操作後的return值。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章