簡體   English   中英

Java 中已檢查與未檢查的異常

[英]Checked vs Unchecked Exceptions in Java

我在理解 Java 中已checkedunchecked異常之間的差異時遇到了一些問題。

  1. 首先, checked異常應該在編譯時尋找異常。 不同來源中提供的示例引用了數據庫連接、文件處理作為其中的一些,而unchecked異常應該尋找程序員方面的錯誤,例如索引超出數組范圍等。

不應該反過來嗎? 我的意思是,數據庫連接是在運行時完成的,對嗎? 文件處理也是如此。 您在編譯期間不打開文件句柄,那么為什么在編譯期間查找可能的錯誤呢? 另一方面,對超出范圍的數組進行索引已經在程序中完成,可以在編譯時檢查(如果異常索引是用戶在運行時提供的,那么它是一個運行時也可以)問題)。 我在這里缺少什么?

2 其次, RunTimeException本身如何uncheckedunchecked ,子類Exceptionchecked 這意味着什么?

我在 Herbert Schildt 的書中找到了一個例子,解釋了checked異常的用法:

class ThrowsDemo {
   public static char prompt(String str)
      throws java.io.IOException {
  System.out.print(str + ": ");
  return (char) System.in.read();
  }
  public static void main(String args[]) {
    char ch;
    try {
      ch = prompt("Enter a letter");
    }
    catch(java.io.IOException exc) {
     System.out.println("I/O exception occurred.");
     ch = 'X';
    }
    System.out.println("You pressed " + ch);
    }
}

這里是否需要throws子句? 為什么我不能用像這樣的try-catch語句正常地做到這一點(對不起,我不知道如何模擬IO Exception ,所以無法自己檢查!):

class ThrowsDemo {
   public static char prompt(String str)  {
     System.out.print(str + ": ");
     return (char) System.in.read();
  }
  public static void main(String args[]) {
    char ch;
    try {
      ch = prompt("Enter a letter");
    }
    catch(java.io.IOException exc) {
     System.out.println("I/O exception occurred.");
     ch = 'X';
    }
    System.out.println("You pressed " + ch);
    }
}

CheckedException 需要由調用者處理,Unchecked 異常不需要。

所以,當你設計你的應用程序時,你應該記住你正在管理什么樣的特殊情況。

例如,如果您設計了一個驗證方法來檢查某些用戶輸入的有效性,那么您知道調用者必須檢查驗證異常並以美觀的方式向用戶顯示錯誤。 這應該是一個已檢查的異常。

或者,對於那些可以恢復的異常情況:假設您有一個負載平衡器,並且您想通知調用方“n”個服務器中的一個已關閉,因此調用方必須恢復事件並將消息重新路由到另一台服務器; 這應該是一個已檢查的異常,因為調用者(客戶端)嘗試恢復錯誤至關重要,而不要讓錯誤破壞程序流程。

相反,有許多情況不應該發生,和/或應該破壞程序。 例如,編程錯誤(如被零除、空指針異常)、API 的錯誤使用(IllegalStateException、OperationNotSupportedException)、硬件崩潰或一些無法恢復的小情況(與服務器的連接丟失),或世界末日:-); 在這些情況下,正常處理是讓異常到達代碼的最外層塊,該塊向用戶顯示發生了不可預測的錯誤並且應用程序無法繼續執行任何操作。 這是一種致命的情況,因此您唯一能做的就是將其打印到日志中或在用戶界面中向用戶顯示。 在這些情況下,捕獲異常是錯誤的,因為捕獲異常后您需要手動停止程序以避免進一步損壞; 所以最好讓某種異常“擊中風扇”:)

由於這些原因,JRE 中還有一些未檢查的異常:OutOfMemoryError(不可恢復)、NullPointerException(這是一個需要修復的錯誤)、ArrayIndexOutOfBoundsException(另一個錯誤示例)等等。

我個人認為 SQLException 也應該取消檢查,因為它表示程序中的錯誤,或者與數據庫的連接問題。 但是有很多例子你會得到異常,你真的不知道如何管理(RemoteException)。

處理異常的最好方法是:如果你能恢復或管理異常,就處理它。 否則讓異常通過; 其他人將需要處理。 如果您是最后一個“其他人”並且您不知道如何處理異常,只需顯示它(在 UI 中記錄或顯示)。

  1. 您不需要在throws子句中聲明未經檢查的異常; 但你必須聲明受檢異常;
  2. RuntimeExceptionError ,以及它們的所有子類( IllegalArgumentExceptionStackOverflowError等),都是 unckecked 異常; 與其他Throwable子類不同, RuntimeException是未經檢查的,這是設計Throwable
  3. 沒有“編譯時異常”這樣的東西。

更一般地,認為在 JVM 錯誤或程序員錯誤的情況下會拋出未經檢查的異常。 一個著名的此類異常是NullPointerException ,通常縮寫為 NPE,它是RuntimeException的子類,因此未經檢查。

未檢查異常和已檢查異常之間的另一個非常重要的區別是,在 try-catch 塊中,如果要捕獲未檢查異常,則必須明確地捕獲它們

最后一點:如果您有異常類E1E2並且E2擴展E1 ,那么捕獲和/或拋出E1也會捕獲/拋出E2 這代表已檢查和未檢查的異常。 這對catch塊有一個含義:如果您確實區分了捕獲E2E1 ,則必須先捕獲E2

例如:

// IllegalArgumentException is unchecked, no need to declare it
public void illegal()
{
    throw new IllegalArgumentException("meh");
}

// IOException is a checked exception, it must be declared
public void ioerror()
    throws IOException
{
    throw new IOException("meh");
}

// Sample code using illegal(): if you want to catch IllegalArgumentException,
// you must do so explicitly. Not catching it is not considered an error
public void f()
{
    try {
        illegal();
    } catch (IllegalArgumentException e) { // Explicit catch!
        doSomething();
    }
}

我希望這能讓事情更清楚......

  1. 不。所有異常都發生在運行時。 受檢異常是強制調用者處理或聲明它們的異常。 它們通常用於指示可恢復的錯誤,這些錯誤不是由程序員錯誤引起的(例如文件不存在,或網絡連接問題)。 運行時異常通常用於表示不可恢復的錯誤。 它們不會強制調用者處理或聲明它們。 它們中的許多確實表示編程錯誤(如 NullPointerException)。

  2. 因為這就是 JLS 定義未檢查異常的方式:屬於或擴展 RuntimeException 的異常,它本身擴展了 Exception。 使用單個繼承根允許在單個 catch 子句中處理每個可能的異常。

關於您的示例:是的,throws 子句是強制性的,因為 IOException 是一個已檢查的異常,並且該方法內的代碼容易拋出異常。

編譯器只確保一個方法在沒有聲明它的情況下不能拋出一個已檢查的異常。 人們普遍認為,編譯器應該對發生在程序員控制之外的異常進行此類檢查,例如您引用的示例(數據庫連接、文件丟失等)。 未經檢查的異常“不應該發生”,因此編譯器不會強迫您聲明它們。

至於模擬IOException或任何其他,它是微不足道的:

throw new IOException();

在您的示例中, prompt方法可能會拋出IOException ,這就是它需要聲明它的原因。 這與您在調用方法時如何處理異常無關。

RuntimeExceptionException一個子類,它可以方便地使用一個catch Exception子句捕獲所有異常。 這本來可以設計成不同的; Java 的異常類層次結構一團糟。

如果你不在這里放 throws 子句,就會出現這個錯誤

ThrowsDemo.java:5: 未報告的異常 java.io.IOException; 必須被捕獲或聲明被拋出 return (char) System.in.read();

所以在必要時拋出子句。

已檢查異常和未檢查異常的五個示例。

Unchecked Exception
   -- NullPointerException
   -- ArrayIndexOutofBound
   -- IllegalArgument Exception
   -- ClassCastException
   -- IllegalStateException
   -- ConcurrentModificationException

Checked Exception Five Example
   -- FileNotFoundException
   -- ParseException
   -- ClassNotFoundException
   -- CloneNotSupportException
   -- SQLException

檢查和未檢查異常

有兩種類型的異常:已檢查異常和未檢查異常。 已檢查異常和未檢查異常之間的主要區別在於,已檢查異常在編譯時檢查,而未檢查異常在運行時檢查。

請閱讀這篇文章以獲得一個清晰的想法。

更多細節

當客戶端代碼可以根據異常信息采取一些有用的恢復操作時,使用檢查異常。 當客戶端代碼不能做任何事情時,使用未經檢查的異常。 例如,如果客戶端代碼可以從中恢復,則將您的 SQLException 轉換為另一個已檢查的異常;如果客戶端代碼對此無能為力,則將您的 SQLException 轉換為未檢查的(即 RuntimeException)異常。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM