手记

Java异常处理的10个最佳实践

异常处理在编写健壮的Java应用中扮演着非常重要的角色。异常处理并不是功能性需求,它需要优雅地处理任何错误情况,比如资源不可用、非法的输入、null输入等等。Java提供很多异常处理特性,通过内置的try、catch、finally关键字实现。Java同样允许创建新的异常和使用throw和throws抛出该异常。在实践中,异常处理不单单是知道语法这么简单。编写健壮的代码更像是一种艺术,而不是一门科学,在接下来的文章中,我们将讨论Java异常处理的最佳实践。这些最佳实践遵循标准的JDK库,以及几个开源代码库,来更好地应对错误和异常处理。这还是为Java程序员提供的编写健壮代码的袖珍参考手册。

编程中异常处理的最佳实践

这里是我收集的Java编程中异常处理的10个最佳实践。大家对Java中的受检异常(checkedException)褒贬不一,这种语言特性要求该异常必须被处理。在本文中,我们尽可能少使用受检异常,同时也要学会在Java编程中,区别使用受检和非受检异常。

1)为可恢复的错误使用受检异常,为编程错误使用非受检异常。

对Java开发者来说,选择受检还是非受检异常总是让人感到困惑。受检异常保证你会针对错误情况提供异常处理代码,这是一种从语言层面上强制你编写健壮代码的一种方式,但同时也引入大量杂乱的代码并导致其可读性变差。当然,如果你有可替代方式或恢复策略的话,捕获异常并做处理看起来似乎也合情合理。在Java编程中选择受检异常还是运行时异常的更多信息,请参考checkedvsuncheckedexceptions。

2)在finally程序块中关闭或者释放资源

这是Java编程中一个广为人知的最佳实践和一个事实上的标准,尤其是在处理网络和IO操作的时候。在finally块中关闭资源能保证无论是处于正常还是异常执行的情况下,资源文件都能被合理释放,这由finally语句块保证。从Java7开始,新增加了一项更有趣的功能:自动资源管理,或者称之为ARM块。尽管如此,我们仍然要记住在finally块中关闭资源,这对于释放像FileDescriptors这类资源至关重要,因为它在socket和文件操作中都会被用到。

3)在堆栈信息中包含引起异常的原因

Java库和开源代码在很多情况下会将一种异常包装成另一种异常。这样记录和打印根异常就变得非常重要。Java异常类提供了getCause()方法来获取导致异常的原因,这可以提供更多有关异常发生的根本原因的信息。这条实践对调试或排除故障大有帮助。在把一个异常包装成另一种异常时,记住需要把源异常传递给新异常的构造器。

4)始终提供异常的有意义的完整信息

异常信息是最重要的,在其中,你能找到问题产生的原因,因为这是出问题后程序员最先看到的地方。记得始终提供精确的真实的信息。例如,对比下面两条IllegalArgumentException的异常信息:

message1:“Incorrectargumentformethod”message2:“Illegalvaluefor${argument}:${value}

第一条消息仅说明了参数是非法的或不正确的,但第二条消息包括了参数名和非法值,这对找到错误原因很重要。在编写异常处理代码的时候,应当始终遵循该Java最佳实践。

5)避免过度使用受检异常

受检异常的强制性在某种程度上具有一定的优势,但同时它也使得代码可读性变差,混淆了正常的业务逻辑代码。你可以通过适度使用受检异常来最大限度地减少这类情况的发生,这样可以得到更简洁的代码。你同样可以使用Java7的新功能,比如在一个catch语句中捕获多个异常,以及自动管理资源,以此来移除一些冗余的代码。

6)将受检异常转为运行时异常

这是在诸如Spring之类的框架中用来减少使用受检异常的方式之一,大部分JDBC的受检异常都被包装进DataAccessException中,DataAccessException异常是一种非受检异常。这个最佳实践带来的好处是可以将特定的异常限制到特定的模块中,比如把SQLException抛到DAO层,把有意义的运行时异常抛到客户端层。

7)记住异常的性能代价高昂

需要记住的一件事是异常代价高昂,同时让代码运行缓慢。假如你有一个方法从ResultSet中进行读取,它经常会抛出SQLException而不是将cursor移到下一元素,这将会比不抛出异常的正常代码执行的慢的多。因此最大限度的减少不必要的异常捕捉,去修复真正的根本问题。不要仅仅是抛出和捕捉异常,如果你能使用boolean变量去表示执行结果,可能会得到更整洁、更高性能的解决方案。修正错误的根源,避免不必要的异常捕捉。

8)避免空的catch块

没有什么比空的catch块更糟糕的了,因为它不仅隐藏了错误和异常,同时可能导致你的对象处于不可用状态或者脏状态。空的catch块没有意义,除非你非常肯定异常不会以任何方式影响对象的状态,但在程序执行期间,用日志记录错误依然是最好的方法。这在Java异常处理中不仅仅是一个最佳实践,而且是一个最通用的实践。

9)使用标准异常

第九条最佳实践是建议使用标准和内置的Java异常。使用标准异常而不是每次创建我们自己的异常,这对于目前和以后代码的可维护性和一致性,都是最好的选择。重用标准异常使代码可读性更好,因为大部分Java开发人员对标准的异常更加熟悉,比如JDK中的RuntimeException,IllegalStateException,IllegalArgumentException,NullPointerException,他们能立马知道每种异常的目的,而不是在代码或文档里查找用户自定义异常的目的。

10)为方法抛出的异常编写文档

Java提供了throw和throws关键字来抛出异常,在javadoc中可以用@throw为任何可能被抛出的异常编写文档。如果你编写API或者公共接口,这就变得非常重要。当任何方法抛出的异常都有相应的文档记录时,就能潜在的提醒任何调用该方法的开发者。

以上这些就是所有在Java异常处理需要遵循的最佳实践。如果你有异常处理更好的最佳实践,请务必让我们知道。

15人推荐
随时随地看视频
慕课网APP