Day42--異常向上丟擲

1hahahahahahahaha發表於2024-12-07

Day42--異常向上丟擲

  1. 方法呼叫棧的概念

    • 在Java程式執行過程中,方法之間會相互呼叫,當一個方法呼叫另一個方法時,就會形成一個方法呼叫棧。棧底是main方法(程式的入口),隨著方法的呼叫,新的方法被壓入棧頂。例如,main方法呼叫methodAmethodA又呼叫methodB,那麼此時棧頂是methodB,中間是methodA,棧底是main方法。
  2. 異常向上層丟擲的過程

    • 當在一個try塊中發生異常,並且沒有合適的catch塊來處理這個異常時,異常會沿著方法呼叫棧向上傳播。也就是說,異常會從當前方法丟擲,回到呼叫該方法的上層方法中。
    • 例如,假設有三個方法method1method2method3method3在執行過程中出現了異常,並且沒有處理這個異常,那麼這個異常會從method3丟擲,回到呼叫method3method2中。如果method2也沒有處理這個異常,異常會繼續向上傳播到呼叫method2method1中,以此類推,直到異常被處理或者到達main方法。如果異常一直傳播到main方法都沒有被處理,那麼程式就會終止,並在控制檯列印出異常資訊。
  3. 示例程式碼說明

    • 假設有以下程式碼結構:
    public class ExceptionPropagation {
        public static void method3() {
            int[] arr = {1, 2, 3};
            System.out.println(arr[3]); // 這裡會丟擲ArrayIndexOutOfBoundsException異常
        }
        public static void method2() {
            method3();
        }
        public static void method1() {
            try {
                method2();
            } catch (ArithmeticException e) {
                System.out.println("捕獲到ArithmeticException");
            }
        }
        public static void main(String[] args) {
            method1();
        }
    }
    
    • 以下是結合上述程式碼詳細說明在方法呼叫棧中各個呼叫方法的位置所在以及位置變化情況:

      初始狀態

      程式從 main 方法開始執行,此時方法呼叫棧中只有一個元素,即 main 方法處於棧底位置,此時棧的情況如下:

      棧內位置 方法名
      棧底 main

      main 方法呼叫 method1

      當執行到 main 方法裡呼叫 method1 的語句時,method1 方法被壓入棧中,此時 method1 位於棧頂,main 方法在棧底,呼叫棧結構變為:

      棧內位置 方法名
      棧頂 method1
      棧底 main

      method1 呼叫 method2

      method1 方法內部執行呼叫 method2 的語句後,method2 方法被壓入棧頂,此時棧內從上到下依次是 method2method1main,結構如下:

      棧內位置 方法名
      棧頂 method2
      中間 method1
      棧底 main

      method2 呼叫 method3

      接著,method2 方法裡呼叫 method3method3 會被壓入棧頂,此時棧內元素順序變為 method3 在最頂部,然後依次是 method2method1main,具體如下:

      棧內位置 方法名
      棧頂 method3
      第二層 method2
      第三層 method1
      棧底 main

      method3 中丟擲異常後

      method3 方法執行到 System.out.println(arr[3]); 丟擲 ArrayIndexOutOfBoundsException 異常時,由於 method3 本身沒有處理這個異常,異常開始沿著方法呼叫棧向上傳播。此時 method3 的執行會立即停止,它依然處於棧頂位置,但即將要被彈出棧,棧的情況暫時還是:

      棧內位置 方法名
      棧頂 method3
      第二層 method2
      第三層 method1
      棧底 main

      異常傳播到 method2

      隨著異常向上傳播,method3 會被彈出棧(因為它已經執行不下去了,且異常要傳遞給上層方法),此時 method2 成為棧頂,棧內剩下 method2method1main,結構如下:

      棧內位置 方法名
      棧頂 method2
      第二層 method1
      棧底 main

      不過因為 method2 同樣沒有處理該異常的程式碼,它也沒辦法繼續執行下去,同樣即將被彈出棧,異常繼續向上傳播。

      異常傳播到 method1

      method2 被彈出棧後,method1 變為棧頂,此時棧內只有 method1main,如下:

      棧內位置 方法名
      棧頂 method1
      棧底 main

      method1 裡的 catch 塊是用來捕獲 ArithmeticException 的,無法捕獲當前的 ArrayIndexOutOfBoundsException 異常,所以 method1 也執行不下去了,會被彈出棧,異常繼續往 main 方法傳播。

      異常傳播到 main 方法時

      method1 被彈出棧後,此時整個方法呼叫棧中就只剩下 main 方法了,它既是棧頂也是棧底,棧的結構變為:

      棧內位置 方法名
      棧頂(也是棧底) main

      由於 main 方法也沒有處理這個異常的程式碼,程式最終會因為這個未處理的異常而終止執行,此時方法呼叫棧也就隨之銷燬了。

      總之,在方法呼叫及異常傳播過程中,方法呼叫棧會動態變化,新呼叫的方法會被壓入棧頂,當出現異常且方法無法處理時,方法會從棧頂依次彈出,異常不斷向上層方法所在的棧位置傳播,直到被處理或者導致程式終止,棧中元素的這種變化順序體現了方法間的呼叫關係以及異常回溯的過程。

異常會向上層丟擲,指的是異常物件本身從當前丟擲異常的方法位置,沿著呼叫棧的層次結構,依次回到呼叫它的上層方法中。

這個疑問的來源:

解釋 Java 中的異常處理機制,包括try-catch-finally語句塊的執行流程。

  • 首先執行try塊中的程式碼,如果在try塊中沒有發生異常,則跳過catch塊,直接執行finally塊(如果有finally塊),然後繼續執行try-catch-finally語句塊之後的程式碼。
  • 如果在try塊中發生了異常,則立即停止try塊中剩餘程式碼的執行,根據異常的型別去匹配catch塊中的異常型別,如果匹配成功,則執行對應的catch塊中的程式碼,處理完異常後,再執行finally塊(如果有)。如果沒有匹配到合適的catch塊,則異常會向上層丟擲,直到被處理或者導致程式終止。
  • finally塊中的程式碼無論是否發生異常都會被執行,通常用於釋放資源等操作,如關閉檔案流、資料庫連線等,哪怕try塊中使用了return語句,finally塊依然會執行,並且如果finally塊中有return語句,會覆蓋trycatch塊中的return結果哦(這是個容易混淆的點,也可以提及一下)。
    你上面說的“如果沒有匹配到合適的catch塊,則異常會向上層丟擲”,這是啥意思?什麼叫向上層丟擲

相關文章