Java API和已检查/未检查的异常混淆

时间:2017-01-16 21:13:38

标签: java exception

关于已检查和未检查的例外的问题在这里和其他网站上提出了数百万次,但我仍然对这些不同的答案感到困惑。

在许多答案和文章中,我们可以阅读一般性陈述,如:

  

未经检查的运行时异常通常表示条件   说来,反映程序逻辑中的错误而不是   从运行时间合理地恢复。

和已检查的例外

  

表示在即时控制之外的区域中的无效条件   程序(用户输入无效,数据库问题,网络中断,   缺席文件)

两个引号均来自http://www.javapractices.com/topic/TopicAction.do?Id=129,并被多次引用。

我们可以在oracle网站上阅读类似的声明:

  

运行时异常表示由a产生的问题   编程问题,因此,API客户端代码不能   合理地预计会从他们身上恢复或处理它们   办法   http://docs.oracle.com/javase/tutorial/essential/exceptions/runtime.html

让我们看一下使用扫描仪读取数字的简单示例:

Scanner sc = new Scanner(System.in);
int userInput = sc.nextInt();
System.out.println(userInput);
当我输入" asdf"

nextInt()抛出InputMismatchException。而不是int。 InputMismatchException是RuntimeException但是根据上面的语句,这是已检查异常的第一个例子"无效的用户输入"。

当我查看已检查的异常时,我更加困惑。例如NPE vs FileNotFoundException - 两者都可以通过简单的if-else来阻止,那么为什么第一个被取消选中而第二个被检查?

Oracle网站有底线指南:

  

如果可以合理地期望客户从异常中恢复,   使它成为检查异常。如果客户端无法做任何事情来恢复   从异常中,将其作为未经检查的例外。

所以根据我可以从FileNotFoundException或IOException恢复,但我不能从NPE或ArrayIndexOutOfBoundsException?这毫无意义。

也许有人用更好的例子对此有更好的解释?

2 个答案:

答案 0 :(得分:0)

非常简单和事实:

  • 未经检查的异常(Runtime类和子级)传达意外异常。 一般来说,调用者不应该知道如何处理它,也不会在任何情况下等待它。

  • 检查异常会传达一个异常,您可以将其视为“正常”异常,并且调用者知道如何处理它。这对他来说可能不是名义上的情况,但来电者知道它可能会发生,应该做好准备处理它。

在你的例子中:

  当我输入“asdf”时,

nextInt() throws InputMismatchException   而不是int。 InputMismatchExceptionRuntimeException但是   根据上面的陈述,这是第一个检查的例子   例外情况“用户输入无效”。

当方法调用nextInt()时,调用者等待int值。这是例外情况。如果不是这种情况,用户会更愿意:next()检索一个String对象,然后尝试通过适合的东西进行转换。
当您调用nextInt()时,调用者会根据请求等待int。迫使他处理InputMismatchException,因为选中的Exception会违反直觉。

  

所以根据我可以从FileNotFoundException或   IOException但我不能从NPE或ArrayIndexOutOfBoundsException?   这毫无意义。

我认为JDK Exceptions为FileNotFoundExceptionIOException是特殊情况。可能不一定检查它们,因为这些类的客户端等待找不到文件或者流在读取或写入期间产生一些异常,而是因为流可能处于不合适的状态并因此引发许多外部原因(文件已锁定,缺少权限,文件移至另一个地方或无法访问的网络等等)。 生成异常的文件可能被认为是处理重要的事情。 因此,JDK规范更喜欢调用者明确地处理它。

此外,在try-with-resources语句到达之前,调用者应该在异常的情况下显式关闭流。

NPEArrayIndexOutOfBoundsException通常是编程错误。应用程序无法进行处理以特别恢复它不知道存在的错误。那么为什么要检查它们?

答案 1 :(得分:-3)

您的应用中可能会或可能无法恢复每个例外情况。它总是取决于上下文。如果某个对象为null并且您获得NPE(未选中),则可能会导致空表达式语言表达式(因此在此特定上下文中,这种情况是完全可恢复的)。另一方面,您可能会收到无法恢复的IOException(已检查),因为您的Web应用程序无法连接到数据库,因此在此特定Web应用程序的上下文中无用。

  

也许有人对此有更好的解释

有一个更好的解释:制作检查和未检查的异常只是语言作者的错误设计决策。只要java保持向后兼容,它的决定就不会被改变。

所以只是:

  1. 忽略这种人为分裂(正如其他现代语言所决定的那样)
  2. 设计时你的api总是使用未经检查的
  3. 在处理已检查的异常时,将其置于未选中的深层调用堆栈中(您的生活会更轻松)
  4. 当调用方法时,总是思考/检查它可以抛出(检查或取消选中)的异常,并决定是否应该处理它或重新抛出/通过