23

我在理解 Java 中的差异checkedunchecked异常方面遇到了一些问题。

  1. 首先,checked异常应该在编译期间寻找异常。不同来源中提供的示例引用了数据库连接、文件处理作为其中的一些,而unchecked异常应该查找程序员方面的错误,例如超出数组范围的索引等。

不应该反过来吗?我的意思是,数据库连接是在运行时完成的,对吧?文件处理也是如此。您不会在编译期间打开文件句柄,那么为什么在编译期间寻找可能的错误呢?另一方面,超出范围的数组的索引已经在程序中完成,可以在编译时检查(如果异常索引是用户在运行时提供的,那么它可以是运行时问题)。我在这里想念什么?

2 其次,怎么可能RunTimeException,本身就是unchecked,子类Exception,哪个是checked?这意味着什么?

我在 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);
    }
}
4

8 回答 8

29

CheckedException 需要由调用者处理,Unchecked 异常不需要。

所以,当你设计你的应用程序时,你应该考虑到你正在管理什么样的异常情况。

例如,如果您设计了一个验证方法来检查某些用户输入的有效性,那么您知道调用者必须检查验证异常并以美观的方式向用户显示错误。这应该是一个检查异常。

或者,对于那些可以恢复的异常情况:假设您有一个负载均衡器,并且您想通知调用者“n”个服务器之一已关闭,因此调用者必须恢复事件,将消息重新路由到另一台服务器;这应该是一个已检查的异常,因为调用者(客户端)尝试恢复错误至关重要,不要让错误破坏程序流程。

相反,有许多情况不应该发生,和/或应该破坏程序。例如,编程错误(如除以零、空指针异常)、错误使用 API(IllegalStateException、OperationNotSupportedException)、硬件崩溃或一些不可恢复的小情况(与服务器的连接丢失),或世界末日:-);在这些情况下,正常的处理是让异常到达代码的最外层,向用户显示发生了不可预知的错误并且应用程序无法继续执行。这是一种致命的情况,因此您唯一能做的就是将其打印到日志中或在用户界面中将其显示给用户。在这些情况下,捕获异常是错误的,因为,捕获异常后,您需要手动停止程序以避免进一步的损坏;所以最好让某种异常“打击粉丝”:)

由于这些原因,JRE 中也有一些未检查的异常:OutOfMemoryError(不可恢复)、NullPointerException(这是一个需要修复的错误)、ArrayIndexOutOfBoundsException(另一个错误示例)等等。

我个人认为 SQLException 也应该不选中,因为它表示程序中的错误或与数据库的连接问题。但是有很多例子你得到异常,你真的不知道如何管理 (RemoteException)。

处理异常的最佳方法是:如果您可以恢复或管理异常,请处理它。否则让异常过去;其他人将需要处理。如果您是最后一个“其他人”并且您不知道如何处理异常,只需显示它(记录或显示在 UI 中)。

于 2012-12-23T15:33:55.370 回答
8
  1. 您不需要在throws子句中声明未经检查的异常;但您必须声明已检查的异常;
  2. RuntimeExceptionError,以及它们的所有子类(IllegalArgumentExceptionStackOverflowError),都是未受检异常;RuntimeException与其他子类不同,未经检查的事实是Throwable设计使然;
  3. 没有“编译时异常”之类的东西。

更一般地,认为在发生 JVM 错误或程序员错误时会抛出未经检查的异常。一个著名的例外是NullPointerException,通常缩写为 NPE,它是 的子类RuntimeException,因此不受检查。

未经检查的异常和检查的异常之间的另一个非常重要的区别是,在 try-catch 块中,如果要捕获未经检查的异常,则必须显式地捕获它们

最后说明:如果您有异常类E1和扩展,那么捕获E2和/或抛出也捕获/抛出。这代表已检查和未检查的异常。这对块有影响:如果你区分catch和,你必须先catch 。E2E1E1E2catchE2E1E2

例如:

// 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();
    }
}

我希望这能让事情更清楚......

于 2012-12-23T14:36:57.423 回答
7
  1. 不,所有异常都发生在运行时。已检查异常是强制调用者处理或声明它们的异常。它们通常用于指示可恢复的错误,这些错误不是由程序员错误引起的(例如文件不存在或网络连接问题)。运行时异常通常用于表示不可恢复的错误。他们不会强迫调用者处理或声明它们。其中许多确实表示编程错误(如 NullPointerException)。

  2. 因为这就是 JLS 定义未经检查的异常的方式:一个是或扩展 RuntimeException 的异常,它本身扩展了 Exception。使用单个继承根允许在单个 catch 子句中处理每个可能的异常。

关于您的示例:是的, throws 子句是强制性的,因为 IOException 是一个已检查的异常,并且该方法内的代码很容易抛出一个。

于 2012-12-23T14:40:28.897 回答
2

编译器仅确保方法在未声明的情况下不会抛出已检查异常。人们普遍认为,编译器应该对发生超出程序员控制范围的异常进行此类检查,例如您引用的示例(数据库连接、文件丢失等)。未经检查的异常“不应该发生”,因此编译器不会强制您声明它们。

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

throw new IOException();

在您的示例中,该prompt方法可能会抛出一个IOException,这就是它需要声明它的原因。这与您在调用方法时如何处理异常无关。

RuntimeException是一个子类,Exception可以方便地用一个catch Exception子句捕获所有异常。这可以设计不同;Java 的异常类层次结构是一团糟。

于 2012-12-23T14:37:55.253 回答
1

如果你不在这里放 throws 子句,就会出现这个错误

ThrowsDemo.java:5:未报告的异常 java.io.IOException;必须被捕获或声明被抛出 return (char) System.in.read();

所以在必要时抛出子句。

于 2012-12-23T14:38:42.437 回答
1

已检查异常和未检查异常的五个示例。

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

Checked Exception Five Example
   -- FileNotFoundException
   -- ParseException
   -- ClassNotFoundException
   -- CloneNotSupportException
   -- SQLException
于 2016-03-24T15:15:51.807 回答
0

已检查和未检查的异常

有两种类型的异常:已检查的异常和未检查的异常。已检查异常和未检查异常之间的主要区别在于,已检查异常在编译时检查,而未检查异常在运行时检查。

请阅读这篇文章以获得清晰的想法。

于 2014-08-22T05:52:06.697 回答
0

更多细节

当客户端代码可以根据异常中的信息采取一些有用的恢复操作时,使用已检查的异常。当客户端代码不能做任何事情时使用未经检查的异常。例如,如果客户端代码可以从中恢复,则将您的 SQLException 转换为另一个已检查的异常;如果客户端代码对此无能为力,则将您的 SQLException 转换为未经检查的(即 RuntimeException)异常。

于 2015-12-23T13:23:39.357 回答