昨天的面試官居然是位小姐姐,聊了半個多小時的異常處理

萬貓學社發表於2022-03-09

大風吹去了往日的霧霾,陽光透過窗戶照進來,透過窗戶可以看到遠處的山脈與藍天相接,這可比我那永遠見不到陽光的出租屋好多了。漸漸走進的腳步聲打斷了我的思緒,一位小姐姐坐在了面前,甜甜的香水味立刻鑽進了我的鼻孔。

小姐姐微笑地說:”您好,我是今天的面試官,那麼開始吧?“

我收起直勾勾的眼睛,說:“好的。”

小姐姐說:“在Java的異常處理中有兩大組成要素:丟擲異常和捕獲異常。那麼丟擲異常可以分為哪兩種呢?”

我立刻回答到:

丟擲異常可以分為顯式和隱式。顯式拋異常是在程式碼中使用throw關鍵字手動將異常例項丟擲。隱式拋異常是 Java 虛擬機器在執行過程中,遇到無法繼續執行的異常狀態,自動將異常例項丟擲,比如我們經常遇到的空指標異常(NullPointerException)。

小姐姐說:“很好,那麼捕獲異常中經常用到哪些關鍵字呢?”

我立刻回答到:

我們一般用到trycatchfinally等關鍵字。try被用來標記需要進行異常監控的程式碼;catch被用來捕獲在try 監控的程式碼中觸發的某種指定型別的異常,還可以定義針對該異常型別進行如何處理;finally被用來宣告一段無論發生什麼異常都必定執行的程式碼,它避免跳過某些關鍵的清理程式碼,比如:關閉已開啟的IO資源。

小姐姐說:“很好,如果三個關鍵字一起使用,程式碼執行的順序是什麼樣子的?”

我立刻回答到:

在正常執行的情況下,先執行try中的程式碼再執行finally中的程式碼。

如果try中的程式碼觸發異常,並且異常沒有被捕獲,finally中程式碼會被直接執行,並且在執行之後重新丟擲該異常;如果異常被catch捕獲,先執行catch中的程式碼再執行finally中的程式碼。

如果catch中的程式碼也觸發了異常,那麼finally中程式碼同樣會被執行,並會丟擲catch程式碼觸發的那個異常。如果finally中的程式碼也觸發了異常,那麼會中斷當前finally 程式碼的執行,並丟擲異常。

小姐姐說:“很好,在Java虛擬機器中,是通過什麼方式實現異常處理?”

這個問題有點難度,我稍微思考了一下回答到:

主要是通過異常表。在編譯生成的位元組碼中,每個方法都附帶一個異常表。異常表中可能有多條記錄,每一條記錄都包括from指標、to 指標、target指標和所捕獲的異常型別。這些指標的值是位元組碼索引(bytecode index),用於定位位元組碼。

其中,from指標和to指標表示異常處理監控的範圍,比如: try所覆蓋的範圍。target指標指向異常處理程式碼的起始位置,比如:catch程式碼的起始位置。

如果有異常觸發時,Java虛擬機器會從上至下遍歷異常表中的所有記錄。當觸發異常的位元組碼的索引值在某個異常表記錄的監控範圍內,Java虛擬機器會判斷所丟擲的異常和該記錄想要捕獲的異常是否匹配。如果匹配,控制流轉將會移至該記錄 target 指標指向的位元組碼。

小姐姐說:“有點抽象,可以舉個例子嗎?”

“當然可以。”我一邊說,一邊在紙上寫了起來:

public class OneMore {

    public static void main(String[] args) {
        String str = "萬貓學社";
        try {
            str = "try";
        } catch (Exception e) {
            str = "catch";
        }
    }
}

這段程式碼的 main 方法中,我定義了一段trycatch 程式碼。編譯過後的位元組碼中,這個方法的異常表擁有一個記錄:

public static void main(java.lang.String[]);
  descriptor: ([Ljava/lang/String;)V
  flags: ACC_PUBLIC, ACC_STATIC
  Code:
    stack=1, locals=3, args_size=1
       0: ldc           #2                  // String 萬貓學社
       2: astore_1
       3: ldc           #3                  // String try
       5: astore_1
       6: goto          13
       9: astore_2
      10: ldc           #5                  // String catch
      12: astore_1
      13: return
    Exception table:
       from    to  target type
           3     6     9   Class java/lang/Exception

from指標和to指標分別為 3 和 6,代表它的監控範圍從索引為 3 的位元組碼開始,到索引為 6 的位元組碼結束(不包括 6)。該記錄的 target 指標是 9,代表這個異常處理從索引為 9 的位元組碼開始。該記錄的最後一列,代表該異常處理所捕獲的異常型別是Exception

當觸發異常的位元組碼的索引值在 3 和 6 之間時,Java虛擬機器會判斷所丟擲的異常是否時Exception。如果是,控制流轉將會移至索引為 9 的位元組碼開始執行。

小姐姐滿意地說:“很好,我去叫HR和你聊聊,如果順利的話,今天就可以發offer。”


參考文獻:
《Java程式設計思想》
《Java核心技術》
《深入理解Java虛擬機器:JVM高階特性與實踐》


竟然已經看到這裡了,你我定是有緣人,留下你的點贊關注,他日必成大器。

微信公眾號:萬貓學社

微信掃描二維碼

關注後回覆「電子書」

獲取12本Java必讀技術書籍

昨天的面試官居然是位小姐姐,聊了半個多小時的異常處理

相關文章