在Java中观察到一种惯例,即在处理Checked Exception后立即重新抛出RuntimeException。
这种方式有好处也有坏处。当编译器强制通过Checked Exception处理某些内容时,开发人员可以通过捕获并将其重新抛出为RuntimeException来摆脱它。
请问是否有人能解释这种情况是否可以被视为良好的实践?如果是这样,这种方法是否会减少错误或使代码库不稳定?
在Java中观察到一种惯例,即在处理Checked Exception后立即重新抛出RuntimeException。
这种方式有好处也有坏处。当编译器强制通过Checked Exception处理某些内容时,开发人员可以通过捕获并将其重新抛出为RuntimeException来摆脱它。
请问是否有人能解释这种情况是否可以被视为良好的实践?如果是这样,这种方法是否会减少错误或使代码库不稳定?
实际上,是对处理已检查异常的无能力尝试导致了代码库的不稳定性。通常情况下,您会看到这种情况:
try {
//stuff
} catch (IOException e) {
log.error("Failed to do stuff", e);
throw e;
}
然后,你将不得不再次处理它,通常会记录所有内容并使日志文件混乱。如果您不重新抛出异常,情况将变得更糟:
try {
// do stuff
} catch (IOException e) {
return null;
}
现在调用代码不知道出了什么问题,更别提具体是什么了。与那些尝试相比,这实际上正是应用逻辑所需的:
try {
// do stuff
} catch (IOException e) {
throw new RuntimeException(e);
}
现在异常可以自由传播到调用栈,直到它到达定义良好的异常边界,在此处:
简而言之,要决定是捕获和处理还是捕获和重新抛出,只需问自己这个问题:
这种异常的发生是否必须中止当前工作单元?
凭借多年的实际经验,我可以告诉您,超过90%的所有可能的已检查异常都属于“中止”类型,在发生的地方不需要处理。
今天,已检查异常被广泛认为是语言设计上的失败实验,以下是其关键论点:
API创建者无权决定其异常在客户端代码中的语义。
Java的论据是异常可分为:
尽管这种划分在一定程度上是真实存在的,但只能从客户端代码的角度定义。更重要的是,在实践中这种划分并不是非常相关:真正重要的是什么时候必须处理异常。如果要在异常边界处晚期处理它,那么检查异常并没有任何好处。如果要早期处理,那么只有在某些情况下才有轻微的检查异常收益。
实践证明,检查异常提供的任何收益都被现实生活中对真实项目造成的损害所淹没,每个Java专业人士都有所见。Eclipse和其他IDE也应该承担责任,它们建议经验不足的开发人员将代码包装在try-catch中,然后想知道在catch块中写什么。
每当您遇到一个抛出异常的方法时,您就会发现另一个检查异常缺陷的活生证明。
throws CheckedException
),否则对此不做任何处理,让调用者处理或以相同方式声明它。 - devconsoleRuntimeException
或Error
。这个事实是无法避免的。 - Marko Topolnik有太多的已检查异常被捕获...并静默忽略。
如果你看看 Scala,他们也放弃了它 - 它只是为了 Java 兼容性而存在。
在 Oracle 网站上的这个教程中,你会找到这个定义:
如果客户端可以合理地预期从异常中恢复,则将其作为已检查的异常。
如果客户端无法对异常进行任何恢复操作,则将其作为未经检查的异常。
这个概念在 Scala 中也被采用,而且很好用。
从技术上讲,你的提议是行得通的。无论哪种方式都需要纪律和代码审查。
try {
} catch (Exception e){
e.printStacktrace();
}
try {
} catch (Exception e){
//try to do something useful
throw new RuntimeException(e);
}
SQLException
),在没有停止和重置线程的情况下无法恢复。您捕获它,尝试在其中进行一些操作(如重置某些内容、关闭打开的套接字等),然后抛出一个RuntimeException()
。
< p > RuntimeException将挂起整个线程,避免程序继续执行,就好像什么都没有发生。此外,您能够管理其他异常而不仅仅是打印它们。根据上下文,这可能是可以的,也可能不可以,但可能性不大。
概括而言,RuntimeExceptions 应仅用于指示编程错误(例如 IllegalArgumentException 和 IllegalStateException)。它们不一定是可检查的异常,因为您通常假设您的程序正确无误,直到证明存在问题,且您无法以有意义的方式处理这些异常(必须发布更新版本的程序)。
另一个有效使用运行时异常的方法是在使用会捕获和处理异常的框架时。在这种情况下,如果您不打算处理这个异常,那么在每个方法中声明异常只会变得繁琐。
因此,总体而言,我认为将已检查异常重新抛出为运行时异常是非常不好的做法,除非您有一个能够正确处理它的框架。
FileNotFoundException
既可以是编程错误,也可以是不幸的运行时情况。 - Marko Topolnik