JavaRush /Java Blog /Random-TW /Java中的異常(Java Exception)

Java中的異常(Java Exception)

在 Random-TW 群組發布
在日常生活中,有時會出現一些我們沒有預料到的情況。例如,您早上起床去上班,尋找手機充電器,但沒有。你去浴室洗臉——水已經停了。我上了車,車卻發動不起來。但一個人能夠輕易地應對這種不可預見的情況。在本文中,我們將嘗試弄清楚 Java 程式如何處理它們。

什麼是java異常

在程式設計世界中,程式執行過程中出現錯誤和意外情況稱為異常。在程式中,由於不正確的使用者操作、磁碟上缺少必要的資源或透過網路與伺服器的連線遺失,可能會發生異常。程式執行過程中的異常也可能是由於程式錯誤或 API 使用不當造成的。與我們的世界不同,程式必須清楚知道在這種情況下該怎麼做。Java 為此提供了異常機制。

簡單介紹一下關鍵字try、catch、finally、 throws

Java中的例外處理是基於在程式中使用以下關鍵字:
  • try - 定義可能發生異常的程式碼區塊;
  • catch – 定義處理異常的程式碼區塊;
  • finally – 定義一個可選的程式碼區塊,但如果存在,則無論如何都會執行,無論 try 區塊的結果如何。
這些關鍵字用於在程式碼中建立特殊處理結構:try{}catch、try{}catch{}finally、try{}finally{}。
  • throw-用於引發異常;
  • throws-用在方法簽章中,警告該方法可能拋出例外。
在 Java 程式中使用關鍵字的範例:
//method reads a string from the keyboard

public String input() throws MyException {//warn with throws,
// that the method can throw MyException
      BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
    String s = null;
// in the try block we enclose the code in which an exception can occur, in this
// if the compiler tells us that the readLine() method of the class
// BufferedReader may throw an I/O exception
    try {
        s = reader.readLine();
// in the catch block we enclose the code for handling the IOException exception
    } catch (IOException e) {
        System.out.println(e.getMessage());
// close the read stream in the finally block
    } finally {
// when closing the stream, an exception is also possible, for example, if it was not opened, so we “wrap” the code in a try block
        try {
            reader.close();
// write exception handling when closing the read stream
        } catch (IOException e) {
            System.out.println(e.getMessage());
        }
    }

    if (s.equals("")) {
// we decided that an empty string could disrupt the work of our program in the future, for example, on the result of this method, we need to call the substring(1,2) method, so we are forced to interrupt the program execution with the generation of our exception type MyException using throw
        throw new MyException("String can not be empty!");
    }
    return s;
}

為什麼我們需要異常機制?

讓我們來看一個現實世界的例子。想像一下,高速公路上有一段路段有一座承載力有限的緊急橋。如果質量超過橋樑承載能力的車輛駛過橋樑,橋樑可能會倒塌,溫和地說,駕駛員的情況可能會變得異常。為了防止這種情況發生,道路服務部門提前在道路上安裝了警告標誌。汽車駕駛看著警告標誌,會將汽車的重量與允許在橋上行駛的重量進行比較。如果超過了,他就會繞道而行。由於道路服務部門的行動,卡車司機首先有機會提前改變路線,其次警告他們主幹道上有危險,最後警告他們不能使用特定條件下的橋樑。
Исключения в Java - 2
能夠防止和解決程式中的異常,使其能夠繼續運行,這是在 Java 中使用異常的原因之一。異常機制還允許您透過驗證(檢查)傳入資料來保護您編寫的程式碼(程式設計介面)免於使用者誤用。現在讓我們暫時當一下交通警察。首先,您應該了解駕駛者可能遇到麻煩的地方。其次,您需要準備並安裝警示標誌。最後,您需要提供繞行路線,以防主路線上出現危險。在Java中,異常機制的工作原理與此類似。在程式開發階段,我們使用try{}區塊「保護」程式碼中的危險部分免受異常影響,使用catch{}區塊提供「備份」路徑,並在finally{}區塊中編寫在為任何結果制定計劃。當我們無法提供「緊急路線」或故意把選擇權留給使用者時,我們至少必須警告他有危險。為什麼?想像一下,當一名駕駛到達一座緊急橋樑時,沿途沒有遇到任何一個警告標誌,就無法駛過,他會多麼憤怒!在程式設計中,在編寫我們的類別和方法時,我們總是無法預見其他開發人員在程式中使用它們的上下文,因此我們無法預見解決異常情況的 100% 正確路徑。同時,警告我們程式碼的使用者可能出現異常也是一種很好的做法。Java 的異常機制允許我們透過使用 throws 來做到這一點——本質上是聲明我們的方法拋出異常的一般行為,從而讓該方法的使用者編寫程式碼來處理 Java 中的異常。

「麻煩」警告

當您不打算在方法中處理異常,但想要警告方法的使用者可能出現異常時,請使用 throws 關鍵字。方法簽章中的此關鍵字意味著在某些條件下該方法可能會引發異常。此警告是方法介面的一部分,並賦予使用者自訂異常處理程序的實作的權利。在 throws 之後,我們指示拋出的異常類型。這些通常是Java Exception類別的後代。由於Java是物件導向的語言,因此Java中的所有異常都是物件。
Исключения в Java - 3

Java異常層次結構

當程式執行期間​​發生錯誤時,JVM 執行階段會從 Java 異常層次結構建立所需類型的物件 - 從公共「祖先」(Throwable 類別)繼承的一組可能的異常。程式中出現的異常情況可分為兩類:
  1. 無法恢復程式進一步正常運作的情況
  2. 恢復是可能的。
第一組包括發生從Error類別繼承的異常的情況。這些錯誤是在程式執行期間​​因 JVM 故障、記憶體溢位或系統崩潰而發生的錯誤。它們通常表明無法使用軟體修復的嚴重問題。Java中的此類異常在編譯階段被歸類為未檢查異常。該群組還包括 RuntimeException - 異常,Exception類別的繼承者,由 JVM 在程式執行期間​​產生。它們通常是由程式錯誤引起的。這些異常在編譯時也不受檢查,因此無需編寫程式碼來處理它們。第二組包括在編寫程式階段預見的異常情況,並且必須為此編寫處理程式碼。檢查此類異常。Java 開發人員在處理異常時的大部分工作就是處理此類情況。

創建異常

程式執行過程中,異常由JVM拋出或手動使用throw語句拋出。這會在記憶體中建立一個異常物件併中斷主程式碼的執行,同時 JVM 異常處理程序會嘗試找到處理異常的方法。

例外處理

我們在 Java 中提供異常處理的程式碼區塊的建立是在程式中使用 try{}catch、try{}catch{}finally、try{}finally{} 建構完成的。
Исключения в Java - 4
當 try 區塊中引發異常時,將在下面的 catch 區塊中尋找異常處理程序。如果 catch 包含此類異常的處理程序,則控制權將傳遞給它。如果沒有,JVM 在方法呼叫鏈中尋找該異常類型的處理程序,直到找到合適的 catch。執行 catch 區塊後,控制權將傳遞給可選的finally區塊。如果找不到合適的 catch 區塊,JVM 將停止程式執行並顯示方法呼叫堆疊 -堆疊跟踪,其中先前已執行過 finally 區塊程式碼(如果存在)。異常處理範例:
public class Print {

     void print(String s) {
        if (s == null) {
            throw new NullPointerException("Exception: s is null!");
        }
        System.out.println("Inside method print: " + s);
    }

    public static void main(String[] args) {
        Print print = new Print();
        List list= Arrays.asList("first step", null, "second step");

        for (String s:list) {
            try {
                print.print(s);
            }
            catch (NullPointerException e) {
                System.out.println(e.getMessage());
                System.out.println("Exception was processed. Program continues");
            }
            finally {
                System.out.println("Inside bloсk finally");
            }
            System.out.println("Go program....");
            System.out.println("-----------------");
        }

    }
    }
主要方法 的結果:
Inside method print: first step
Inside bloсk finally
Go program....
-----------------
Exception: s is null!
Exception was processed. Program continues
Inside bloсk finally
Go program....
-----------------
Inside method print: second step
Inside bloсk finally
Go program....
-----------------
此區塊finally通常用於關閉在 try 區塊中開啟的串流或釋放資源。然而,在編寫程式時,並不總是能夠追蹤所有資源的關閉情況。為了讓我們的生活更輕鬆,Java 開發人員為我們提供了一個結構try-with-resources,可以自動關閉在 try 區塊中開啟的資源。我們的第一個例子可以這樣重寫try-with-resources
public String input() throws MyException {
    String s = null;
    try(BufferedReader reader = new BufferedReader(new InputStreamReader(System.in))){
        s = reader.readLine();
   } catch (IOException e) {
       System.out.println(e.getMessage());
   }
    if (s.equals("")){
        throw new MyException ("String can not be empty!");
    }
    return s;
}
由於Java的功能,從版本7開始,我們還可以將不同類型異常的捕獲組合在一個區塊中,使程式碼更加緊湊和可讀。例如:
public String input() {
    String s = null;
    try (BufferedReader reader = new BufferedReader(new InputStreamReader(System.in))) {
        s = reader.readLine();
        if (s.equals("")) {
            throw new MyException("String can not be empty!");
        }
    } catch (IOException | MyException e) {
        System.out.println(e.getMessage());
    }
    return s;
}

結果

在Java中使用異常允許我們透過使用「備份」路徑來提高程式的容錯能力,透過使用catch區塊將主程式碼的邏輯與異常處理程式碼分開,並且還使我們有機會委託使用throws 對程式碼的使用者進行異常處理。
還有什麼要讀的:

關於 Java 異常的十大問題

留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION