Java 中的已选中与未选中的异常

2022-09-01 22:19:46

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

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

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

2 其次,它本身如何成为子类,哪个是?这是什么意思?RunTimeExceptionuncheckedExceptionchecked

我在赫伯特·希尔德特(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);
    }
}

该条款在这里是必要的吗?为什么我不能用这样的语句正常地做到这一点(对不起,我不知道如何模拟一个,所以不能自己检查!throwstry-catchIO 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);
    }
}

答案 1

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

因此,在设计应用程序时,应牢记要管理的特殊情况。

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

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

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

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

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

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


答案 2
  1. 您不需要在子句中声明未经检查的异常;但您必须声明选中的异常;throws
  2. RuntimeException和 ,以及它们的所有子类 (, etc), 都是未被忽略的例外;与其他子类不同,未经检查的事实是设计使然;ErrorIllegalArgumentExceptionStackOverflowErrorRuntimeExceptionThrowable
  3. 没有“编译时异常”这样的事情。

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

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

最后一个注意事项:如果你有异常类和和 extends,那么捕获和/或抛出也会捕获/抛出。这代表已选中和未选中的异常。这对块有影响:如果你区分 catch 和 ,你必须先 catch。E1E2E2E1E1E2catchE2E1E2

例如:

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

我希望这能让事情变得更清晰...