java 中的finally你知多少_Java 处理异常 9 个最佳实践,你知道几个?
1. 在Finally中清理资源或者使用Try-With-Resource语句使用Finally
Java 7的Try-With-Resource语句
2. 给出准确的异常处理信息
3. 记录你所指定的异常
4. 使用描述性消息抛出异常
5. 最先捕获特定的异常
6. 不要在catch中使用Throwable
7. 不要忽略Exceptions
8. 不要记录和抛出一个异常
9. 包装异常
总结
在本文中,作者介绍了9个处理异常的最佳方法与实践,以举例与代码展示结合的方式,让开发者更好的理解这9种方式,并指导读者在不同情况下选择不同的异常处理方式。
以下为译文:
Java中的异常处理不是一个简单的话题。初学者很难理解,甚至有经验的开发人员也会花几个小时来讨论应该如何抛出或处理这些异常。
这就是为什么大多数开发团队都有自己的异常处理的规则和方法。如果你是一个团队的新手,你可能会惊讶于这些方法与你之前使用过的那些方法有多么不同。
然而,有几种异常处理的最佳方法被大多数开发团队所使用。下面是帮助改进异常处理的9个最重要的方法。
1. 在Finally中清理资源或者使用Try-With-Resource语句
通常情况下,你在try中使用了一个资源,比如InputStream,之后需要关闭它。在这种情况下,一个常见的错误是在try的末尾关闭了资源。
public void doNotCloseResourceInTry() {
FileInputStream inputStream = null;
try {
File file = new File("./tmp.txt");
inputStream = new FileInputStream(file);
// use the inputStream to read a file
// do NOT do this
inputStream.close();
} catch (FileNotFoundException e) {
log.error(e);
} catch (IOException e) {
log.error(e);
}
}
问题是,只要不抛出异常,这种方法就可以很好地运行。try内的所有语句都将被执行,资源也会被关闭。
但是你在try里调用了一个或多个可能抛出异常的方法,或者自己抛出异常。这意味着可能无法到达try的末尾。因此,将不会关闭这些资源。
所以应该将清理资源的代码放入Finally中,或者使用Try-With-Resource语句。
使用Finally
相比于try,无论是在成功执行try里的代码后,或是在catch中处理了一个异常后,Finally里的内容是一定会被执行的。因此,可以确保清理所有已打开的资源。
public void closeResourceInFinally() {
FileInputStream inputStream = null;
try {
File file = new File("./tmp.txt");
inputStream = new FileInputStream(file);
// use the inputStream to read a file
} catch (FileNotFoundException e) {
log.error(e);
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
log.error(e);
}
}
}
}
Java 7的Try-With-Resource语句
另一个选择是Try-With-Resource语句,在introduction to Java exception handling中更详细地说明了这一点。
如果你的资源实现了AutoCloseable接口,就可以使用它,这正是大多数Java标准资源所做的。当你在try子句中打开资源时,它将在try被执行后自动关闭,或者处理一个异常。
public void automaticallyCloseResource() {
File file = new File("./tmp.txt");
try (FileInputStream inputStream = new FileInputStream(file);) {
// use the inputStream to read a file
} catch (FileNotFoundException e) {
log.error(e);
} catch (IOException e) {
log.error(e);
}
}
2. 给出准确的异常处理信息
你抛出的异常越具体越好。一定要记住,一个不太了解你代码的同事,也许几个月后,需要调用你的方法,并且处理这个异常。
因此,请确保提供尽可能多的信息,这会使你的API更容易理解。因此,你方法的调用者将能够更好地处理异常,或者通过额外的检查来避免它。
所以,要尽量能更好地描述你的异常处理信息,比如用NumberFormatException代替IllegalArgumentException,避免抛出一个不具体的异常。
public void doNotDoThis() throws Exception {
...
}
public void doThis() throws NumberFormatException {
...
}
3. 记录你所指定的异常
当你在方法中指定一个异常时,你应该在Javadoc中记录下它。这与前面提到的方法有着相同的目标:为调用者提供尽可能多的信息,这样他们就可以避免异常或者更容易地处理异常。
因此,请确保在Javadoc中添加一个@throws 声明,并描述可能导致的异常情况。
/**
\* This method does something extremely useful ...
*
\* @param input
\* @throws MyBusinessException if ... happens
*/
public void doSomething(String input) throws MyBusinessException {
...
}
4. 使用描述性消息抛出异常
这一最佳实践的理念与前两个相似。但这一次,你不用给调用方法的人提供信息。异常消息会被所有人读取,同时必须了解在日志文件或监视工具中报告异常时发生了什么。
因此,应该尽可能准确地描述问题,并提供相关的信息来了解异常事件。
别误会,你不需要写一段文字,而是应该用1-2个简短的句子解释异常的原因。这可以帮助开发团队理解问题的严重性,同时也使你能够更容易地分析任何服务事件。
如果抛出一个特定的异常,它的类名很可能已经描述了这种类型的错误。所以,你不需要提供很多额外的信息。一个很好的例子就是,当你以错误的格式使用字符串时,如NumberFormatException,它就会被类 java.lang.Long的构造函数抛出。
try {
new Long("xyz");
} catch (NumberFormatException e) {
log.error(e);
}
NumberFormatException已经告诉你问题的类型,所以只需要提供导致问题的输入字符串。如果异常类的名称不具有表达性,那么就需要提供必要的解释信息。
17:17:26,386 ERROR TestExceptionHandling:52 - java.lang.NumberFormatException: For input string: "xyz"
5. 最先捕获特定的异常
大多数IDE都可以帮助你做到这点,当你试图捕获不确定的异常时,它会报告一个不可到达的代码块。
问题是只有第一个匹配到异常的catch语句才会被执行,所以,如果你最先发现IllegalArgumentException,你将永远不会到达catch里处理更具体的NumberFormatException,因为它是IllegalArgumentException的一个子类。
所以要首先捕获特定的异常类,并在末尾添加一些处理不是很具体异常的catch语句。
你可以在下面的代码片段中看到这样一个try-catch语句的示例。第一个catch处理所有NumberFormatExceptions异常,第二个catch 处理NumberFormatException异常以外的illegalargumentexception异常。
public void catchMostSpecificExceptionFirst() {
try {
doSomething("A message");
} catch (NumberFormatException e) {
log.error(e);
} catch (IllegalArgumentException e) {
log.error(e)
}
}
6. 不要在catch中使用Throwable
Throwable是exceptions 和 errors的父类。当然,你可以在catch子句中使用它,但其实你不应该这样做。
如果你在catch子句中使用Throwable,它将不仅捕获所有的异常,还会捕获所有错误。JVM会抛出错误,这是应用程序不打算处理的严重问题。典型的例子是OutOfMemoryError或StackOverflowError。这两种情况都是由应用程序控制之外的情况引起的,无法处理。
所以,最好不要在catch中使用Throwable,除非你完全确定自己处于一个特殊的情况下,并且你需要处理一个错误。
public void doNotCatchThrowable() {
try {
// do something
} catch (Throwable t) {
// don't do this!
}
}
7. 不要忽略Exceptions
你是否曾经分析过只有用例的第一部分才被执行的bug报告吗?
这通常是由一个被忽略的异常引起的。开发人员可能非常确信它不会被抛出,并添加一个无法处理或无法记录它的catch语句。当你发现它的时候,你很可能就会明白一句著名的话“This will never happen”。
public void doNotIgnoreExceptions() {
try {
// do something
} catch (NumberFormatException e) {
// this will never happen
}
}
是的,你可能在分析一个不可能发生的问题。
所以,请千万不要忽略一个例外。你不会知道代码在将来会发生什么变化。有些人可能会删除阻止异常事件的验证,而没有意识到这造成了问题。或者抛出异常的代码被更改,现在抛出了同一个类的多个异常,而调用的代码并不能阻止所有这些异常。
你至少应该写一个日志信息,告诉每个人,需要检查一下这个问题。
public void logAnException() {
try {
// do something
} catch (NumberFormatException e) {
log.error("This should never happen: " + e);
}
}
8. 不要记录和抛出一个异常
这可能是最常被忽略的。你可以在许多代码片段或者库文件里发现,有异常会被捕获、记录和重新抛出。
try {
new Long("xyz");
} catch (NumberFormatException e) {
log.error(e);
throw e;
}
当它发生时记录一个异常,然后重新抛出它,以便调用者能够适当地处理它,这可能会很直观。但是它会为同一个异常写多个错误消息。
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条。
public void wrapException(String input) throws MyBusinessException {
try {
// do something
} catch (NumberFormatException e) {
throw new MyBusinessException("A message that describes the error.", e);
}
}
因此,只需要捕获一个你想要处理的异常,在方法中指定它,并让调用者处理它。
9. 包装异常
有时最好捕获一个标准异常并将其封装到一个定制的异常中。此类异常的典型例子是应用程序或框架特定的业务异常。这允许你添加额外的信息,并且也可以为异常类实现一个特殊的处理。
当你这样做时,确保引用原始的异常处理。Exception类提供了一些特定的构造函数方法,这些方法可以接受Throwable作为参数。否则,你将丢失原始异常的堆栈跟踪和消息,这将使你很难分析导致异常的事件。
public void wrapException(String input) throws MyBusinessException {
try {
// do something
} catch (NumberFormatException e) {
throw new MyBusinessException("A message that describes the error.", e);
}
}
总结
正如你所看到的,在抛出或捕获异常时,有许多不同的事情需要考虑。以上大多数方法都可以提高代码可读性或API可用性。
异常通常是一个错误处理机制和一个通信媒介。因此,你应该确保同事一起讨论想要应用的最佳实践和方法,以便每个人都理解通用概念并以相同的方式使用它们。
java 中的finally你知多少_Java 处理异常 9 个最佳实践,你知道几个?相关推荐
- java中字母用什么单词赋值_Java初学
Java-SUN 语言平台J2SE(桌面) ,J2ME(移动被安卓所取代),J2EE(企业主要用于web) 1.跨平台(操作系统)原理: 在任意操作系统上运行,一次编写到处运行. 依赖JVM(Java ...
- java中main函数的值是_java基础-main方法
概述 Java中的main方法,是一个java应用程序的入口,无论一个java的应用多么复杂庞大,或是多么的小,只要他是一个可以运行的java程序那么必然就要有一个main方法.main方法的定义格式 ...
- java中父类创建子类的语法_Java 语言中,所创建的子类都应有一个父类。( )_学小易找答案...
[判断题]一个类可以实现多个接口,接口可以实现"多重继承". ( ) [简答题]报价议价环节话术 [单选题]定义一个公有double型常量PI,哪一条语句最好?( ) [论述题]展 ...
- java中基本字节输出流类是_java中基本输入输出流的解释
网络程序的很大一部分是简单的输入输出,即从一个系统向另一个系统移动字节.字节就是字节,在很大程度上,读服务器发送的数据与读取文件没什么不同:向客户传送数据与写入一个文件也没有什么区别. Java中输入 ...
- java中char是几个字节_Java中char占用几个字节
在讨论这个问题之前,我们需要先区分unicode和UTF. unicode :统一的字符编号,仅仅提供字符与编号间映射.符号数量在不断增加,已超百万.详细:[https://zh.wikipedia. ...
- java中的常用的文件流_Java 基础(四)| IO 流之使用文件流的正确姿势
image.png 一.什么是 IO 流? 想象一个场景:我们在电脑上编辑文件,可以保存到硬盘上,也可以拷贝到 U 盘中.那这个看似简单的过程,背后其实是数据的传输. 数据的传输,也就是数据的流动.既 ...
- java中什么时候不能用泛型_java中泛型的正确使用姿势
image.png 泛型是Java中一个非常重要的知识点,在Java集合类框架中泛型被广泛应用.利用好泛型,在系统架构中是一把利器. 泛型类 先看一个例子,restful架构中,需要定义api接口返回 ...
- java中的进制输出转换_Java I/O : Java中的进制详解
作者:李强强 上一篇,泥瓦匠基础地讲了下Java I/O : Bit Operation 位运算.这一讲,泥瓦匠带你走进Java中的进制详解. 一.引子 在Java世界里,99%的工作都是处理这高层. ...
- JAVA中希尔排序去的讲解_java 中基本算法之希尔排序的实例详解
java 中基本算法之希尔排序的实例详解 希尔排序(Shell Sort)是插入排序的一种.也称缩小增量排序,是直接插入排序算法的一种更高效的改进版本.希尔排序是非稳定排序算法.该方法因DL.Shel ...
最新文章
- Linux获取系统当前时间(精确到毫秒)
- 正则表达式 学习笔记1.3
- 电商ERP vs.传统ERP,有何不一样?
- vue隐藏浏览器_一分钟学会Vue的条件渲染和列表渲染
- 【C#桌面应用】第三节:创建一个按钮窗口 您好,世界!
- ArcSDE10.1配置Oracle 监听器来使用SQL操作ST_Geometry(个人改动版)
- 报错:bash: pip: command not found
- AWVS12 安装教程(详细附图)
- 用友T3如何反结账,反记账
- 浏览器怎么导入导出|删除书签,方法步骤来咯
- JS获取下个月的第一天和最后一天
- 百度网站收录批量查询 介绍百度网站收录批量查询3种方式
- [学点经济]什么是SDR [the IMF's Special Drawing Rights (SDR) basket of currencies]
- 【Linux 系统启动优化测试工具的使用——grabserial 】
- 使用CyberController来将旧手机改造成电脑外挂
- 解决Python安装pyqt5-tool出现的系列问题:ERROR: Could not find a version that satisfies the requirement xxx
- 你只管追求卓越,成功自然会尾随而到
- 期货反向跟单—我们与规律同在
- 白帽子讲web安全PDF完整版
- 如何设置电脑默认软件,干货到,电脑默认软件如何设置