在Java(或任何其他带有受控异常的语言)中,当创建您自己的异常类时,您如何决定它应该被检查还是未检查?
我的直觉是,在调用者可能能够以某种有效的方式恢复的情况下,将调用checked异常,而作为未检查的异常则更多地用于不可恢复的情况,但我对其他人的想法感兴趣。
在Java(或任何其他带有受控异常的语言)中,当创建您自己的异常类时,您如何决定它应该被检查还是未检查?
我的直觉是,在调用者可能能够以某种有效的方式恢复的情况下,将调用checked异常,而作为未检查的异常则更多地用于不可恢复的情况,但我对其他人的想法感兴趣。
当前回答
在任何一个足够大的系统上,有很多层,检查异常是无用的,因为无论如何,您需要一个架构级策略来处理异常将如何处理(使用故障屏障)。
使用受控异常,您的错误处理策略是微管理的,在任何大型系统上都无法承受。
大多数情况下,您不知道错误是否“可恢复”,因为您不知道API的调用者位于哪一层。
假设我创建了一个StringToInt API,用于将整数的字符串表示形式转换为Int。如果API是用“foo”字符串调用的,我必须抛出检查异常吗?它可以恢复吗?我不知道,因为在他的层中,我的StringToInt API的调用者可能已经验证了输入,如果抛出这个异常,它要么是一个错误,要么是一个数据损坏,它是不可恢复的这一层。
在这种情况下,API的调用者不想捕获异常。他只想让异常“冒出来”。如果我选择了一个受控异常,这个调用者将有大量无用的catch块,只能人为地重新抛出异常。
大多数时候,什么是可恢复的取决于API的调用者,而不是API的编写者。API不应该使用受控异常,因为只有未受控异常才允许选择捕获或忽略异常。
其他回答
我认为我们可以从以下几个问题来考虑例外:
为什么会发生异常?当它发生时我们能做什么
一个错误,一个bug。如方法调用空对象。
String name = null;
... // some logics
System.out.print(name.length()); // name is still null here
这种异常应该在测试期间修复。否则,它会破坏生产,你会得到一个非常严重的bug,需要立即修复。这种异常不需要检查。
通过来自外部的输入,您不能控制或信任外部服务的输出。
String name = ExternalService.getName(); // return null
System.out.print(name.length()); // name is null here
在这里,如果您希望在名称为空时继续,则可能需要检查名称是否为空,否则,您可以让它单独运行,它将在这里停止并向调用者提供运行时异常。 这种异常不需要检查。
通过来自外部的运行时异常,您不能控制或信任外部服务。
在这里,如果您希望在发生异常时继续执行,则可能需要从ExternalService捕获所有异常,否则,您可以不去管它,它将在这里停止并向调用者提供运行时异常。
通过来自外部的受控异常,您不能控制或信任外部服务。
在这里,如果您希望在发生异常时继续执行,则可能需要从ExternalService捕获所有异常,否则,您可以不去管它,它将在这里停止并向调用者提供运行时异常。
在这种情况下,我们需要知道ExternalService中发生了什么样的异常吗?这取决于:
如果您可以处理某些类型的异常,则需要捕获它们并进行处理。对其他人来说,泡一下。 如果您需要记录或响应用户特定的异常,您可以捕获它们。对其他人来说,泡一下。
我同意将未检查异常作为规则的偏好,特别是在设计API时。调用方总是可以选择捕获记录在案的、未检查的异常。你只是没有必要强迫打电话的人。
I find checked exceptions useful at the lower-level, as implementation detail. It often seems like a better flow of control mechanism than having to manage a specified error "return code". It can sometimes help see the impact of an idea for a low level code change too... declare a checked exception downstream and see who would need to adjust. This last point doesn't apply if there are a lot of generic: catch(Exception e) or throws Exception which is usually not too well-thought out anyway.
来自Java学习者:
When an exception occurs, you have to either catch and handle the exception, or tell compiler that you can't handle it by declaring that your method throws that exception, then the code that uses your method will have to handle that exception (even it also may choose to declare that it throws the exception if it can't handle it). Compiler will check that we have done one of the two things (catch, or declare). So these are called Checked exceptions. But Errors, and Runtime Exceptions are not checked for by compiler (even though you can choose to catch, or declare, it is not required). So, these two are called Unchecked exceptions. Errors are used to represent those conditions which occur outside the application, such as crash of the system. Runtime exceptions are usually occur by fault in the application logic. You can't do anything in these situations. When runtime exception occur, you have to re-write your program code. So, these are not checked by compiler. These runtime exceptions will uncover in development, and testing period. Then we have to refactor our code to remove these errors.
当不太可能出现异常时,即使在捕捉到异常之后,我们也可以继续,并且我们不能做任何事情来避免该异常,那么我们可以使用受控异常。
当我们想做一些有意义的事情时,当一个特定的异常发生时,当这个异常是预期的,但不是确定的,那么我们可以使用受控异常。
当异常在不同的层中导航时,我们不需要在每一层都捕获它,在这种情况下,我们可以使用运行时异常或包装异常作为未检查的异常。
运行时异常是在异常最有可能发生的情况下使用的,没有办法进一步进行,并且没有任何东西可以恢复。在这种情况下,我们可以对这种异常采取预防措施。EX: NUllPointerException, ArrayOutofBoundsException。这些更有可能发生。在这种情况下,我们可以在编码时采取预防措施来避免这种异常。否则,我们将不得不在每个地方都写入try catch块。
更一般的例外情况可以设置为Unchecked,不太一般的例外情况将被检查。
当你想要向调用者提供信息时,受控异常对于可恢复的情况很有用(例如,权限不足,文件未找到等)。
未检查异常很少用于在运行时通知用户或程序员严重错误或意外情况。如果你编写的代码或库将被其他人使用,不要抛出这些异常,因为他们可能不希望你的软件抛出未经检查的异常,因为编译器不会强制捕获或声明这些异常。