原文 | dzone.com/articles/9-…

作者 | Thorben Janssen

翻译 | geekymv

无论你是初学者还是经验丰富的开发人员,对于你和你的团队来说,提高异常处理的能力可以更好的解决问题。

Java中的异常处理并不是一件容易的事,初学者会觉得很难理解,即使是经验丰富的开发人员也可能需要花费几个小时来讨论应该如何抛出或处理哪些异常。

这也是为什么大多数开发团队对于如何使用它们有自己的一套规则。如果你刚加入一个团队,你可能会惊讶这些规则与你之前使用过的规则是多么的不同。

尽管如此,依然有一些最佳实践在大多数团队中被使用。以下9个最重要的方法,可以帮助你开始或提高异常处理。

1、在 finally 代码块中清理资源或使用 try-with-resource 语句

你经常会在try代码块中使用一个资源,比如 InputStream,需要在之后关闭它。在这种情况下的一个常见错误是在try块的末尾关闭资源。

问题是,只要没有抛出异常这种方式可以很好的工作。try 代码块中的语句将被执行,并且资源将被关闭。

但是你添加 try 代码块是有原因的,你调用一个或多个可能抛出异常的方法,或者可能是你自己抛出异常,这意味着你可能未到达try代码块的尾部,最终,你无法关闭资源。

因此,你应该把所有清理代码放在 finally 代码块中,或者使用 try-with-resource 语句。

使用 finally 代码块

与 try 代码块最后几行不同,finally 代码块总是被执行。这种情况发生在 try 代码块成功执行之后,或者在catch 代码块中处理异常之后。因此,你可以确保清理了所有打开的资源。

Java7 中的 Try-With-Resource 语句

另一种方式是 try-with-resource 语句,我在介绍Java异常处理一文中有更详细的说明。

如果你的资源实现了 AutoCloseable 接口,就可以使用它。这是大多数 Java 标准资源所做的。当你在 try 子句中打开资源时,它将在try 代码块执行或者发生异常后自动关闭。

2、首选具体的异常

抛出的异常越具体越好。请记住,一个不知道你的代码的同事,也可能是几个月以后的你,需要调用你的方法并处理异常。

因此,确保提供给他们尽可能多的信息。这使你的API更容易理解。最终,方法的调用者将能够更好地处理异常或通过额外的检查来避免异常。

因此,总是试着找到最合适你的异常事件的类,例如,抛出 NumberFormatException 而不是 IllegalArgumentException。避免抛出一个不具体的异常。

3、为指定的异常编写文档

无论什么时候你在方法签名上指定一个异常时,你都应该在你的Javadoc中为其编写文档。这与之前的最佳实践有同样的目标:提供给调用者尽可能多的信息,以便他可以避免或者处理异常。

因此,确保在你的Javadoc中增加@throws 声明,并且描述可能造成异常的情况。

4、抛出带有描述性信息的异常

这个最佳实践背后的思想和之前两个类似,不同的是,你不用将信息提供给方法的调用者。每个需要了解记录在日志文件或监控工具中异常信息的人,都可以阅读该异常信息。

因此,应该尽可能准确的描述问题,并且提供最相关的信息以了解异常事件。

不要误会我的意思,你不应该写一个文本段落,而是应该用1-2两个短句解释异常的原因。这样可以帮助你的运维团队了解问题的严重性,也可以使你更容易分析任何服务事件。

如果抛出一个具体的异常,它的类名将最可能已经描述了错误的种类。因此,你不需要提供很多额外的信息。一个好的例子是 NumberFormatException。当你提供一个错误的字符串格式时,将由 java.lang.Long 类的构造方法抛出 NumberFormatException 异常。

NumberFormatException 类的名字已经告诉你问题的种类。它的信息仅仅需要提供导致问题的输入字符串。如果异常类的名字不那么具有表现力,则需要在消息中提供必要的信息。

17:17:26,386ERROR TestExceptionHandling:52- java.lang.NumberFormatException: For input string:"xyz"

译者注:可见,给类取个好名字多么重要。

5、优先捕获最具体的异常

大多数 IDE 都可以帮助你实现这个最佳实践。 当你尝试捕获不太具体的异常时,它们会报告一个不可到达的代码块。

问题在于,只有第一个与异常匹配的 catch 代码块才会被执行。因此,如果你首先捕获一个 IllegalArgumentException 异常,你将不能到达应该处理更具体的 NumberFormatException 异常的 catch 代码块。因为它是 IllegalArgumentException 类的子类。

总是首先捕获最具体的异常,然后将不太具体的 catch 代码块添加到列表的尾部。

在下面的代码片段中,你可以看到 try-catch 语句的例子,第一个 catch 代码块处理所有 NumberFormatException 异常,并且第二个 catch 代码块处理所有不属于 NumberFormatException 的 IllegalArgumentException 异常。

6、不要捕获 Throwable

Throwable 是所有 Exception 和 Error 类的父类。你可以在 catch 语句中使用它,但是你绝对不要这样做!

如果你在 catch 语句中使用 Throwable,它不仅捕获所有的 Exception,还将捕获所有的 Error。

Error 是被 JVM 抛出的,它表示不能被应用程序处理的严重问题。典型的例子是 OutOfMemoryError 或 StackOverflowError,都是由应用程序无法控制的情况引起的,并且无法处理。

因此,最好不要捕获 Throwable,除非你绝对确信自己处于能够或需要处理错误的特殊情况下。

7、不要忽略异常

你是否曾经分析过一个bug报告,其中只执行了用例的第一部分?

这通常是由忽略异常引起的,开发者可能很确信它从不会抛出,并且添加了不处理或不打印日志的 catch 代码块,当你找到这个代码块的时候,你甚至可能发现一个著名的注释“This will never happen”。

因此,请不要忽略异常。你不知道代码在未来将如何被改变。有人可能会删除阻止异常事件的验证,而没有意识到这会造成问题。或抛出异常的代码被更改,现在抛出同一个类的多个异常,并且调用代码并不能阻止所有这些异常。

你至少应该写一条日志信息,告诉每个人意想不到的事情刚刚发生了,需要有人来检查它。

8、不要打印日志的同时抛出异常

这可能是列表中最经常被忽略的最佳实践。你可以在许多代码段甚至库中发现异常被捕获、打印日志、并重新抛出。

记录发生的异常,然后将其重新抛出,以便调用者可以适当的处理它,这可能会很直观。但是它将为同一异常写入多个错误信息。

17:44:28,945 ERROR TestExceptionHandling:65 - java.lang.NumberFormatException: For input string: "xyz"Exception in thread "main" java.lang.NumberFormatException: For input string: "xyz"at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)

at java.lang.Long.parseLong(Long.java:589)

at java.lang.Long.(Long.java:965)

at com.stackify.example.TestExceptionHandling.logAndThrowException(TestExceptionHandling.java:63)

at com.stackify.example.TestExceptionHandling.main(TestExceptionHandling.java:58)

额外的消息也没有增加任何信息。正如最佳实践4中所述,异常信息应该描述异常事件。堆栈跟踪会告诉你在哪个类,方法和行中引发了异常。

如果你需要增加额外的信息,你应该捕获异常并且将其包装在自定义异常中,但是请确保遵循最佳实践9。

9、包装异常而不使用它

有时最好是捕获一个异常并将其包装到自定义异常中。这样异常的典型例子是应用程序或框架的具体业务异常。这使你可以增加额外的信息,并且还可以对异常类实现特殊处理。

当你这样做的时候,确保将原始异常设置为原因(cause)。Exception 类提供了接收 Throwable 参数的具体构造方法。否则,你会丢失堆栈跟踪和原始异常的信息,这将使分析导致异常的事件变得困难。

总结

如你所见,当你抛出或捕获异常的时候,你应该考虑很多不同的事情。它们中大多数的目标是提高代码的可读性或API的可用性。

异常通常是一种错误处理机制,同时也是一种通信机制。因此,你应该确保与你的同事讨论你想要应用的最佳实践和规则,以便每个人都理解一般的概念,并以相同的方式使用它们。

作者:Geek_ymv

链接:https://juejin.cn/post/6909838417278959630

来源:掘金

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

java 如何忽略异常_java中如何解决异常相关推荐

  1. Java中非法参数的异常_Java中的异常

    异常指不期而至的各种状况,如:文件找不到.网络连接失败.非法参数等.异常是一个事件,它发生在程序运行期间,干扰了正常的指令流程.Java通 过API中Throwable类的众多子类描述各种不同的异常. ...

  2. java异常类中属于非检测异常的是_下列java语言的常用异常类中,属于检测异常的是()_学小易找答案...

    [单选题]在Word 2010的编辑状态,对当前文档中的文字进行"字数统计"操作,应当使用的菜单是( ) [单选题]客运员领带统一,领带夹夹在衬衣的( )钮扣之间. [单选题]文件 ...

  3. java 文件解析异常_java中异常的解析

    Java Exception: 1.Error 2.Runtime Exception 运行时异常 3.Exception 4.throw 用户自定义异常 异常类分两大类型:Error类代表了编译和系 ...

  4. java常见检查异常_java中常见异常总汇,附解释

    Java Exception: 1.Error 2.Runtime Exception 运行时异常 3.Exception 4.throw 用户自定义异常 异常类分两大类型:Error类代表了编译和系 ...

  5. java gc日志乱码_Java中9种常见的CMS GC问题分析与解决(四)

    目前,互联网上 Java 的 GC 资料要么是主要讲解理论,要么就是针对单一场景的 GC 问题进行了剖析,对整个体系总结的资料少之又少.前车之鉴,后事之师,美团的几位工程师历时一年多的时间,搜集了内部 ...

  6. java中无法推断类型参数_Java中的推断异常

    java中无法推断类型参数 借用和窃取其他语言的概念和想法总是很高兴的. Scala的Option是我真正喜欢的一个主意,因此我用Java编写了一个实现. 它包装了一个可能为null或不为null的对 ...

  7. java 异常处理发生异常_Java中的异常处理

    java 异常处理发生异常 Exception Handling in Java is a very interesting topic. Exception is an error event th ...

  8. java常见的5个异常_Java中常见的五种异常

    1.ClassCastException(类转换异常) 数据类型转换错误,比如有个String temp="abc"; 如果设为(int)temp就会报错了,因为它们类型不一样,但 ...

  9. java中必检异常有哪些_Java中的受检异常

    Java中的受检异常 Java提供了三种异常类型,受检异常(checked exception).运行时异常(runtime exception).错误(error).那么这受检异常在实际开发中又有什 ...

最新文章

  1. Yii2 的小贴士用法
  2. 使用word完成毕业论文的所有详细步骤
  3. Backtrack5中文汉化[转]
  4. webpack - 收藏集 - 掘金
  5. centos7删除文件命令_干货 | 玩转云文件存储——利用CFS实现web应用的共享访问...
  6. Linux下静态库和动态库的编译连接
  7. oracle19c的版本号_Windows10安装Oracle19c数据库详细记录(图文详解)
  8. 很有用很有效的操作之批量操作一组图片
  9. Realme真我X7系列首发骁龙860? 副总裁辟谣:大家散了吧
  10. php 对象转xml字符串_php方法simplexml_load_string()解析xml转数组失败
  11. 空心等腰三角形java_java打印输出任意大小的等腰三角形,实心菱形,空心菱形,平行四边形...
  12. vasp-分子动力学模拟
  13. RS485通讯介绍(附批量测试思路)
  14. 5G到底有多快?和4G相比的直接数据给你更直观感受
  15. python使用微信进行消息推送
  16. access()函数的用法
  17. 小码哥java一期 百度云_小码哥IOS 十一期
  18. 这三年,一路走来,劈荆斩棘 – Vol 2
  19. SAS9.4更新sid,有效期至2022年11月30日
  20. 零基础学编程觉得很枯燥,很难坚持学习下去怎么办?

热门文章

  1. SRS流媒体服务器——Forward集群搭建和源码分析
  2. 基于 iframe 的全新微前端方案
  3. 「递归」第9集 | 我在腾讯做研究
  4. 腾讯云IoT全栈方案助力智慧交通基建,详解四大重点与两个案例
  5. nginx源码分析之变量
  6. Linux shell脚本基础学习详细介绍(完整版)
  7. c++ linux下读取指定目录的所有文件名字
  8. mysql使用某一列的内容赋值给另外一列,concat()函数
  9. spring整合mybatis基于注解
  10. 面试必会系列 - 1.6 Java 垃圾回收机制