我很难理解如何处理未经检查的异常。
如果方法没有声明异常并且我没有被强制处理它,我怎么知道该方法会抛出异常?
未经检查的异常是针对编程错误的,正如我已经读过的那样,为避免NullPointerException
,我会引入空检查。或者对于ArrayIndexOutOfBoundsException
我会检查我如何访问数组。
但是当我不知道一个方法抛出一个自定义的未经检查的异常时,我该如何处理呢?
如何将异常从数据层传播到用户界面?那些必须检查例外,对吗?
我会让数据层抛出DataLayerExceptions
,然后在presenter类中有一个try-catch-block(假设我正在使用MVP),然后在catch-block中设置视图上的错误消息...
或者可以使用未经检查的例外来完成吗?
修改
感谢目前为止的回复。
这是我面临的一个具体例子。
我开始使用Spring,在一本书中,我看到一个UserRepository
类,它使用JDBCTemplate
从数据库中检索数据。 UserRepositoty
包含一个类似这样的方法:
@Override
public List<User> findAll() {
String sql = "select id, username, email, password from p_user";
return new ArrayList<>(jdbcTemplate.query(sql, rowMapper));
}
现在,jdbcTemplate的查询方法抛出DataAccessException
,这是一个运行时异常。
我知道这个,因为我查看了方法签名。
现在,我将如何处理此异常?当然,用户需要某种类型的反馈,以防出现问题。当然,我会记录异常。
但是我会在哪里捕获这个例外?
我应该抓住它然后重新抛出我自己未经检查的异常吗?
或者我应该在DataAccessException
方法上声明抛出findAll
然后处理调用类中的异常(可能是某种服务或演示者)?
或者我应该确保抛出异常的条件永远不会发生(如果那些甚至可以被我控制的话)?
答案 0 :(得分:7)
我很难理解如何处理未经检查的异常。
怎么容易。您处理它们就像检查异常一样。你使用try / catch。 (要抓住所有内容,请抓住RuntimeException
,或抓住Exception
,如果您还想要检查异常。但请注意抓住Error
或Throwable
,并抓住更多例外而不是你期望或者你可以实际处理..)
你真正想知道的是如何知道什么时候会抛出它们。这更难。
正如您所观察到的,语言本身会抛出一些未经检查的异常。理论上,编写代码是可能的,这样就不会发生。在实践中:1)人们犯错误,2)过多的防御性检查是繁重的...而且毫无意义。
其他未经检查的异常显式声明为thrown
,或者记录为在方法或构造函数的javadoc中抛出。 (事实上,我会说设计良好的API 应该记录它预期会抛出或传播的未经检查的异常。)
在问题的情况下,除非您在运行时看到异常,否则您不会了解它。
最后一个案例说明了在开发周期中需要进行彻底的可重复的测试。
但是当我不知道某个方法会抛出一个自定义的未经检查的异常时,我该如何处理它?</ p>
一般来说,你不是。
任何意外异常都应视为错误。您可以在测试中或在生产中找到它。你搞定了。如果你已经正确地修复了它,那么意外的异常就不会再发生......或者它现在是预期的,你的代码会处理它。
结果是,如果你捕获并处理了一个意外的异常,那么你的代码假装没有发生任何错误是一个非常糟糕的主意。至少,需要记录异常,以便程序员可以使用一些东西来找到根本原因。
如何将异常从数据层传播到用户界面?
通常,向用户显示异常(尤其是堆栈跟踪!)是个坏主意。通常情况下,你抓住它们,将它们与堆栈跟踪一起记录......然后告诉用户:&#34;发生了一些不好的事情:请使用以下额外信息向#3报告此信息&#34;
必须检查那些例外,对吧?
模数以上......不。他们不必被检查例外。
我会让数据层抛出已检查的DataLayerExceptions,然后在presenter类中有一个try-catch-block(假设我正在使用MVP),然后在catch-block中设置视图上的错误消息。
你可以这样做。模块化关于向用户显示例外的观点。
显然,如果你打算采用这种方法,你需要能够区分预期的例外,你可以向用户解释,处理和&#34;继续&#34 ;与意料之外的异常无法解释且无法从中恢复。你可能会有一些计划......
最重要的是,没有简单的公式或&#34;最佳实践&#34;这将为你解决这个问题。它需要思考和设计......并且关心......和测试。
答案 1 :(得分:2)
当你写小&#34;学习&#34;应用;那么只是让未经检查的例外情况完全没有问题&#34;起泡&#34;主要方法;甚至在命令行上打印出堆栈跟踪。
在现实世界中#34;应用;你会在某种程度上确保某些东西捕获这样的异常;做以下事情:
换句话说:一个重要的非功能性要求&#34;现实世界&#34;应用程序健壮性。你不希望某个地方缺少一个空检查,这会破坏整个应用程序。因此,您需要确保您的应用程序可以在这种情况下继续运行。 (请注意:我并不是说这些事情很容易实施)。
除此之外:可以使用您自己检查过的异常;但是那里有一个很大的缺点:它们搞砸了你的方法签名。但这是一个高度自以为是的讨论(虽然某些重要的人声称&#34;战争检查与未经检查已结束;并且未经检查赢得了#34;); Oracle的官方文档仍然表明checked例外在现实世界中占有一席之地。
答案 2 :(得分:1)
一般情况下,你应该不会发现完全出乎意料的RuntimeExceptions
。这将是丑陋的(你的代码将充满try-catch语句),并且没有普遍优雅的方法从它们中恢复。
由于编程错误,许多RuntimeExceptions将被抛出,您应该在测试应用程序时修复这些错误。修复导致NullPointerException
导致调用代码可能执行的任何类型捕获和修复的基础错误。
有时,API会抛出您 期望捕获的RuntimeExceptions
(阅读他们的文档)。例如,参数检查可能导致抛出IllegalArgumentException
。在这些情况下,捕获这些特定异常并优雅地处理它们是有意义的(例如,通过将它们重新抛出为自定义检查异常;记住在重新抛出时使用cause
参数)。对于那些IllegalArguments
,您可以将用户的输入标记为无效并请求将其修复。好的API将广泛描述什么时候抛出的东西。阅读the case against checked exceptions以了解为什么任何API程序员想要取消选中而不是检查异常。
然而,正如Ghostcat(伟大的)答案中所见,如果应用程序将拥有用户(超出编程练习),那么{{1}中的隐式catch-everything-and-show-stacktraces绝对应该避免。它们对非开发人员毫无意义,并且没有为实际的开发人员提供足够的上下文,除非他们知道在抛出之前发生了什么。
是一种很好的做法记录任何其他未被捕获的异常,以便您以后可以弄清楚发生了什么。您应该已经使用日志记录来帮助您弄清楚在抛出异常之前发生了什么。
为触发它们的用户提供有用的反馈,以便他们可以对此做些什么。请注意&#34;有用&#34;取决于用户;对于电子商务Web应用程序,只有开发人员才会认为异常细节很有用;虽然买家可以通过友好的,低详细的错误消息得到更好的服务,基本上要求他们稍后重试。
使用自定义检查的异常包装所有未经检查的异常,而不是上述两点是一个坏主意。它没有任何修复:你仍然需要采取上述两个步骤来尝试稍后解决问题。