Java 我该如何让未经检查的异常冒泡并记录?
所以引用了一个名为“异常处理反模式博客”的页面,该页面似乎是由Oracle编写的(或至少是批准的) 未检查的异常可能不应该重试,正确的响应通常是什么也不做,让它从方法中冒出来并通过执行堆栈。这就是为什么不需要在throws子句中声明它。最终,在高级别执行时,可能应该记录异常 我不确定我是否理解这一点。如何记录未检查的异常?如果我有类似于:Java 我该如何让未经检查的异常冒泡并记录?,java,exception,exception-handling,Java,Exception,Exception Handling,所以引用了一个名为“异常处理反模式博客”的页面,该页面似乎是由Oracle编写的(或至少是批准的) 未检查的异常可能不应该重试,正确的响应通常是什么也不做,让它从方法中冒出来并通过执行堆栈。这就是为什么不需要在throws子句中声明它。最终,在高级别执行时,可能应该记录异常 我不确定我是否理解这一点。如何记录未检查的异常?如果我有类似于: public static void main(String args) { foo(); // How do I know what to
public static void main(String args) {
foo();
// How do I know what to log here? The method I am calling
// is not throwing an Exception.
// Do I just blindly catch(Exception ex)?
}
static void foo() {
bar();
}
static void bar() {
baz();
}
static void baz() {
// I will do nothing as Oracle suggests and let this exception bubble up.. I wonder who is going to catch it and how this is going to be logged though!
throw new NullPointerException();
}
try {
bar();
} catch(NullPointerException e) {
throw new HigherLevelException(...);
}
你能帮我理解Oracle的建议吗?我看不到任何直接(或明确)的方法可以在更高级别捕获运行时异常(我不明白为什么它不被称为未检查异常…),我不确定这种建议的做法是否有用。对我来说,如果它讨论的是已检查的异常,则更有意义。类似于
如果在方法中抛出一个已检查的异常,而该方法不适合重新尝试,正确的响应是让它冒泡并记录
您可以像使用try-catch块捕获任何其他异常一样捕获它们。但好处是你不必这么做 用例可能会有所不同。在我看来,最流行的是当在该位置捕获异常没有意义时,或者应该实现比该方法高几个级别(就方法而言)的适当处理,调用抛出异常的方法(抱歉,如果这不够清楚的话) 例如,java中典型的web应用程序布局如下:有一层控制器、一层服务和一层dao。第一个负责调度请求,第二个负责管理业务逻辑,最后一个负责实际调用db。例如,在这里,如果dao级别出现问题,在服务层捕获异常通常没有多大意义。这里可以使用未检查的异常。您记录一个异常并抛出一个未经检查的异常,这样用户就可以在上面的某个级别处理该异常,从而获得对应用程序工作的有价值的反馈 在这种情况下,如果抛出一个选中的异常,您将不得不在上面的每一级对其进行重新排序,以便将其冒泡到实际处理的位置。因此,这里最好使用未经检查的异常,以免复制和粘贴所有丑陋的try-catch块,重新引发异常并将throws子句添加到方法中
public static void main(String[] args) {
try {
foo();
}
catch(NullPointerException e){
System.out.println("NullPointerException in main.");
}
}
static void foo() {
bar();
}
static void bar() {
baz();
}
static void baz() {
// I will do nothing as Oracle suggests and let this exception bubble up.. I wonder who is going to catch it and how this is going to be logged though!
throw new NullPointerException();
}
输出:
NullPointerException in main.
基本上,错误是在更高的级别上出现的,因此不需要在baz()方法级别捕获它。如果我理解正确的话。据我所知,文档建议您在代码的高层有一个通用处理程序,它可以像主方法中的注释所建议的那样记录这种“意外”(不可恢复?)的异常。所以它可能看起来像这样
public static void main(String args) {
try {
foo();
}
catch (ArithmeticException aex) { //if it's arithmetic log differently
log("arith issue! "+aex.getMessage());
}
catch (Exception ex) { //Otherwise do the best we can
log("unknown issue! "+ex.getMessage())
}
}
因此,仍然没有恢复的途径,但至少在过程结束之前,您有机会记录问题。在许多情况下,您还可以使用Exception(或throwable)方法来获取堆栈跟踪和第一个因果异常-因此可能会记录许多额外的有用信息。您还可以注册一个全局异常处理程序,该处理程序将处理代码未捕获的异常:
Thread.setDefaultUncaughtExceptionHandler
然后,此异常句柄可以记录发生的任何事件。我如何知道在此处记录什么?我正在调用的方法没有引发异常。 正如Joshua Bloch在《有效Java》中所建议的那样 使用Javadoc@throws标记记录每个未检查的异常 方法可以抛出,但不要使用throws关键字来包含 方法声明中未检查的异常 如果您在多层应用程序中使用方法包装,我建议您使用异常翻译: 更高的层应该捕获较低级别的异常,并在它们的位置抛出可以用更高级别抽象来解释的异常 看 因此,我认为在你的例子中,实际上你应该使用如下内容:
public static void main(String args) {
foo();
// How do I know what to log here? The method I am calling
// is not throwing an Exception.
// Do I just blindly catch(Exception ex)?
}
static void foo() {
bar();
}
static void bar() {
baz();
}
static void baz() {
// I will do nothing as Oracle suggests and let this exception bubble up.. I wonder who is going to catch it and how this is going to be logged though!
throw new NullPointerException();
}
try {
bar();
} catch(NullPointerException e) {
throw new HigherLevelException(...);
}
首先,这是一个一般性的建议,它取决于上下文。其背后的思想是,当发生运行时异常时(例如,
NullPointerException
),系统通常处于不确定状态,这意味着不能保证其余代码按预期执行,因此最好停止所有操作
在大多数情况下,代码将在单独的线程中运行,异常只会停止当前线程,而程序的其余部分将继续运行
在您的示例中并非如此,因为所有内容都在单个线程中执行,因此未捕获的异常将有效地停止整个程序。在这种情况下,您可能希望捕获异常并处理它
public static void main(String args) {
try {
foo();
catch(Throwable t) {
t.printStackTrace(); // log exception
// handle the failure
}
}
您还可以更早地捕获异常,记录并进一步重试它
static void bar() {
try {
baz();
catch (Throwable t) { // catch
t.printStackTrace(); // log
throw t; // rethrow further
}
}
编辑:捕获可丢弃的而不是异常
,也将捕获错误
注意:捕捉可丢弃的东西通常是一个坏主意,应该只在特定的目的下进行,而不是在一般情况下。请参阅@RC.的注释。有一种非常简单的方法可以捕获未检查的异常,因为它们都是RuntimeException
或Error
的子类:
public static void main(String[] args) {
try {
// your code
} catch (RuntimeException | Error e) {
// handle uncaught exceptions, e.g.
e.printStackTrace();
}
}
关于异常最重要的指导原则是,无法成功完成任务的方法应该抛出异常
只有在能够保证成功完成方法任务的情况下,才应该捕获方法内部的异常(而不重新抛出此异常或其他异常)。根据我的经验,只有在非常特定的情况下才是如此,例如,如果第一次尝试失败,或者如果你真的,你有另一种方法来尝试<