简体   繁体   English

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

[英]Java API and checked/unchecked exceptions confusion

The question about checked and unchecked exceptions was raised here and on other websites million times, but I'm still confused with so different answers. 关于已检查和未检查的异常的问题在这里和其他网站上提出了数百万次,但我仍然对这些不同的答案感到困惑。

In many answers and articles we can read general statements like: 在许多答案和文章中,我们可以阅读以下一般性陈述:

Unchecked runtime exceptions represent conditions that, generally speaking, reflect errors in your program's logic and cannot be reasonably recovered from at run time. 未经检查的运行时异常表示一般来说反映程序逻辑中的错误并且无法在运行时合理恢复的条件。

and for checked exceptions 并且用于检查异常

represent invalid conditions in areas outside the immediate control of the program (invalid user input, database problems, network outages, absent files) 代表程序直接控制范围之外的区域中的无效条件(无效的用户输入,数据库问题,网络中断,缺少文件)

both quotes are from http://www.javapractices.com/topic/TopicAction.do?Id=129 and are cited many times. 这两个引用来自http://www.javapractices.com/topic/TopicAction.do?Id=129并被多次引用。

We can read similar statements on oracle website: 我们可以在oracle网站上阅读类似的声明:

Runtime exceptions represent problems that are the result of a programming problem, and as such, the API client code cannot reasonably be expected to recover from them or to handle them in any way http://docs.oracle.com/javase/tutorial/essential/exceptions/runtime.html 运行时异常表示编程问题导致的问题,因此,无法合理地期望API客户端代码从它们中恢复或以任何方式处理它们http://docs.oracle.com/javase/tutorial/必需/异常/ runtime.html

Lets take simple example with reading Number with Scanner: 让我们看一下使用扫描仪读取数字的简单示例:

Scanner sc = new Scanner(System.in);
int userInput = sc.nextInt();
System.out.println(userInput);

nextInt() throws InputMismatchException when I type ie "asdf" instead of int. 当我键入ie“asdf”而不是int时,nextInt()抛出InputMismatchException。 InputMismatchException is RuntimeException but according to statements above this is the first example of checked exceptions "invalid user input". InputMismatchException是RuntimeException但是根据上面的语句,这是已检查异常“无效用户输入”的第一个示例。

When I look at checked exceptions I am even more confused. 当我查看已检查的异常时,我更加困惑。 For example NPE vs FileNotFoundException - both can be prevented by simple if-else, so why first one is unchecked and second is checked? 例如NPE vs FileNotFoundException - 两者都可以通过简单的if-else来阻止,那么为什么第一个被取消选中而第二个被检查?

Oracle website has bottom line guideline: Oracle网站有底线指引:

If a client can reasonably be expected to recover from an exception, make it a checked exception. 如果可以合理地期望客户端从异常中恢复,则将其作为已检查的异常。 If a client cannot do anything to recover from the exception, make it an unchecked exception. 如果客户端无法执行任何操作以从异常中恢复,请将其设置为未经检查的异常。

So according to that I can recover from FileNotFoundException or IOException but I can't from NPE or ArrayIndexOutOfBoundsException? 所以根据我可以从FileNotFoundException或IOException恢复,但我不能从NPE或ArrayIndexOutOfBoundsException? This makes no sense. 这毫无意义。

Maybe someone has better explanation to this with some better example? 也许有人用一些更好的例子对此有更好的解释?

To be very simple and factual : 要非常简单和事实:

  • an unchecked exception ( Runtime class and children) conveys an unexpected exception. 未经检查的异常( Runtime类和子级)传达意外的异常。 In general, the caller should not know how to handle it and doesn't wait for it in any of his scenarios. 通常,调用者不应该知道如何处理它,并且不会在任何场景中等待它。

  • a checked exception conveys a exception that you may consider as a "normal" exception and the caller know how to handle it. 检查的异常会传达一个异常,您可以将其视为“正常”异常,并且调用者知道如何处理它。 It is probably not the nominal case for him but the caller knows that it could happen and should prepare himself to handle it. 这对他来说可能不是名义上的情况,但是来电者知道它可能发生并且应该准备自己来处理它。

In your example : 在你的例子中:

nextInt() throws InputMismatchException when I type ie "asdf" instead of int. 当我键入ie“asdf”而不是int时, nextInt() throws InputMismatchException InputMismatchException is RuntimeException but according to statements above this is the first example of checked exceptions "invalid user input". InputMismatchExceptionRuntimeException但是根据上面的语句,这是已检查异常“无效用户输入”的第一个示例。

When a method calls nextInt() the caller waits for a int value. 当方法调用nextInt() ,调用者等待int值。 It is the excepted scenario. 这是例外情况。 If it was not the case the user would do rather : next() to retrieve a String object and try then to convert it by something that suits. 如果不是这种情况,用户会这样做: next()检索一个String对象,然后尝试通过适合的东西进行转换。
When you invoke nextInt() , the caller waits for an int as he has requested it. 当你调用nextInt() ,调用者会按照他的请求等待int Force him to handle InputMismatchException as a checked Exception would be counter-intuitive. 强制他处理InputMismatchException因为检查过的Exception会违反直觉。


So according to that I can recover from FileNotFoundException or IOException but I can't from NPE or ArrayIndexOutOfBoundsException? 所以根据我可以从FileNotFoundException或IOException恢复,但我不能从NPE或ArrayIndexOutOfBoundsException? This makes no sense. 这毫无意义。

I think JDK Exceptions as FileNotFoundException or IOException are special cases. 我认为JDK Exceptions为FileNotFoundExceptionIOException是特殊情况。 They are probably checked not necessarily because the client of these classes waits for that the file is not found or the stream generates some exceptions during reading or writing but rather because a stream may be in a not suitable state and consequently raises exception for many external reasons (file locked, lack of right, file moved to another place or to a not reachable network and so for...). 可能不一定检查它们,因为这些类的客户端等待找不到文件或者流在读取或写入期间产生一些异常,而是因为流可能处于不合适的状态并因此因许多外部原因引发异常(文件已锁定,缺少权限,文件移动到另一个地方或无法访问的网络,因此...)。 A file that generates an exception is probably considered as something that is important to handle. 生成异常的文件可能被认为是处理重要的事情。 So, the JDK specification prefers that the caller handles it explicitly. 因此,JDK规范更喜欢调用者明确地处理它。

Besides, before the arrival of the try-with-resources statement, the caller should explicitly close streams in case of exceptions. 此外,在try-with-resources语句到达之前,调用者应该在异常的情况下显式关闭流。


NPE and ArrayIndexOutOfBoundsException are generally programming errors. NPEArrayIndexOutOfBoundsException通常是编程错误。 The application cannot do a processing to recover specifically errors which it doesn't know the existence. 应用程序无法进行处理以特别恢复它不知道存在的错误。 So why make them checked ? 为什么要检查它们呢?

every single exception may or may not be recoverable in your app. 您的应用中可能会或可能无法恢复每个例外。 it always depends on the context. 它总是取决于上下文。 if some object is null and you get NPE (unchecked) it may result in an empty expression language expression (so in this particular context, this situation is perfectly recoverable). 如果某个对象为null并且您获得NPE(未选中),则可能会导致空表达式语言表达式(因此在此特定上下文中,这种情况是完全可恢复的)。 on the other hand, you may get IOException (checked) which is irrecoverable because your web application can't connect to database and therefore is useless in context of this particular web application. 另一方面,您可能会收到无法恢复的IOException(已检查),因为您的Web应用程序无法连接到数据库,因此在此特定Web应用程序的上下文中无用。

Maybe someone has better explanation to this 也许有人对此有更好的解释

there is a better explanation: making checked and unchecked exception was simply a wrong design decision of language authors. 有一个更好的解释:使检查和未检查的异常只是语言作者的错误设计决定。 and it decision won't be changed as long as java remains backward compatible. 只要java保持向后兼容,它就不会改变它的决定。

so just: 所以就:

  1. ignore this artificial division (as other modern languages decided to do) 忽略这种人为的分裂(正如其他现代语言所决定的那样)
  2. when design your api always use unchecked 设计时你的api总是使用未经检查
  3. when working with checked exception, wrap them in unchecked deep down the call stack (your life will be easier) 使用已检查的异常时,将其置于未选中的深层调用堆栈中(您的生活将更容易)
  4. when calling a method always think/check what exceptions it may throw (checked or unchecked) and decide for every one of them if you should handle it or rethrow/pass through 当调用一个方法总是思考/检查它可以抛出(检查或取消选中)的异常并决定它们中的每一个是否应该处理它或重新抛出/通过

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM