在Java中检查vs未经检查的异常

时间:2012-12-23 14:28:25

标签: java exception

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

  1. 首先,checked异常应该在编译期间查找异常。在不同来源中提供的示例引用数据库连接,文件处理作为其中一些,而unchecked异常应该在程序员的部分查找错误,例如超出数组范围的索引等。
  2. 不应该反过来吗?我的意思是,数据库连接是在运行时完成的,对吧?文件处理也是如此。在编译期间没有打开文件句柄,为什么在编译期间会查找可能的错误?另一方面,在程序中已完成索引超出其范围的数组,可在编译期间检查(如果用户在运行时提供异常索引,则可以将其作为运行时)问题)。我在这里缺少什么?

    2其次,RunTimeException本身如何unchecked,子类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);
        }
    }
    

8 个答案:

答案 0 :(得分:25)

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

因此,在设计应用程序时,您应该记住您正在管理的异常情况。

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

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

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

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

我个人认为SQLException也应该是未选中的,因为它表示程序中的错误或数据库的连接问题。但是有许多例子你会得到一个例外,你真的没有任何关于如何管理的线索(RemoteException)。

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

答案 1 :(得分:8)

  1. 您不需要在throws子句中声明未经检查的异常;但是必须声明已检查的例外;
  2. RuntimeExceptionError及其所有子类(IllegalArgumentExceptionStackOverflowError等)都是未确认的异常;与其他RuntimeException子类不同,Throwable未选中的事实是设计的;
  3. 没有“编译时间例外”这样的事情。
  4. 更一般地说,如果出现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();
        }
    }
    

    我希望这会让事情变得更清楚......

答案 2 :(得分:7)

  1. 没有。所有异常都在运行时发生。已检查的异常是强制调用者处理它们或声明它们的异常。它们通常用于发出可恢复错误的信号,这些错误不是由程序员错误(如文件不存在或网络连接问题)引起的。运行时异常通常用于表示不可恢复的错误。它们不会强制调用者处理或声明它们。其中许多确实发出编程错误信号(如NullPointerException)。

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

  3. 关于你的例子:是的,throws子句是​​必需的,因为IOException是一个经过检查的异常,并且方法中的代码很容易抛出一个。

答案 3 :(得分:2)

编译器只确保方法如果没有声明它就不能抛出已检查的异常。一般认为,编译器的这种检查应该针对发生在程序员控制范围之外的异常,例如您引用的示例(数据库连接,文件丢失等)。未经检查的异常“不应发生”,因此编译器不会强制您声明它们。

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

throw new IOException();

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

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

答案 4 :(得分:1)

如果您不在此处放置throws子句,则会发生此错误

ThrowsDemo.java:5:未报告的异常java.io.IOException;必须被抓住或者d 被甩掉了   return(char)System.in.read();

所以抛出必要的条款。

答案 5 :(得分:1)

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

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

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

答案 6 :(得分:0)

已检查和未经检查的例外

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

请阅读此article以获得明确的想法。

答案 7 :(得分:0)

More Details

当客户端代码可以根据异常信息采取一些有用的恢复操作时,使用已检查的异常。客户端代码无法执行任何操作时,请使用未经检查的异常。例如,如果客户端代码可以从中恢复并将SQLException转换为未检查(即RuntimeException)异常(如果客户端代码无法对其执行任何操作),则将SQLException转换为另一个已检查的异常。