异常处理代码必须保证其故障安全机制,其中一条重要的规则如下:

try-catch-finally块抛出的最后一个异常将会在调用堆栈中传递。

所有早期异常将会消失。

如果从一个catchfinally块抛出一个异常,那么这个异常可能会导致try块中捕获的异常隐藏。这会在你试图确定异常的原因时产生误导。

下面是non-fail-safe异常处理的经典示例:

InputStream input = null;
try {
input = new FileInputStream( "myFile.txt" );
/* do something with the stream */
}
catch ( IOException e ) {
throw new WrapperException( e );
}
finally {
try {
input.close();
}
catch ( IOException e ) {
throw new WrapperException( e );
}
}

如果FileInputStream构造器抛出一个FileNotFoundException异常,你认为会发生什么?

首先会执行catch块,该块只会重新抛出包装在WrapperException中的异常。

其次将执行finally块来关闭输入流。但是,由于FileInputStream构造器抛出了一个FileNotFoundException异常,引用变量"input"将为null。结果将是从finally块中抛出NullPointerException异常。NullPointerException不会被catch ( IOException e )子句捕获,所以它将会在调用堆栈中传递。而第一个 catch 块中抛出的WrapperException将会消失。

处理这种情况的正确方式是,在调用任何方法之前,先检查在try块中分配的引用是否为null。比如像下面这样:

InputStream input = null;
try {
input = new FileInputStream("myFile.txt");
//do something with the stream
}
catch(IOException e) {
//first catch block
throw new WrapperException(e);
}
finally {
try {
if(input != null) input.close();
}
catch(IOException e){
//second catch block
throw new WrapperException(e);
}
}

但即使是这样处理同样还是会有问题,让我们先假设"myFile.txt"文件存在,因此"input"引用现在指向一个有效的FileInputStream。同样我们也假设处理输入流时引发了异常,这时第一个 catch 子句捕获后处理并抛出WrapperException,在将WrapperException传递到调用堆栈之前,还要先执行finally子句。如果input.close()调用失败,那么它将会抛出IOException并且被第二个 catch 子句捕获并抛出WrapperException,这时从第一个 catch 子句中抛出的WrapperException再次消失,只有第二个 catch 抛出的WrapperException才会被传递到调用堆栈中。

如你所见,故障安全(fail safe)异常处理并不总是无价值的。InputStream处理示例甚至不是你可以遇到的最复杂的示例。JDBC 中的事务有更多错误的可能性。当尝试提交、然后回滚,最后尝试关闭连接时,可能会出现异常。所有这些可能出现的异常都应该由异常处理代码来处理,因此,他们都不会使第一个被抛出异常消失。这样做的一种方法是确保抛出的最后一个异常包含以前抛出的所有异常,这样开发人员就可以了解错误原因。

BTW,Java 7 中的“try-with-resources”特性使得实现故障安全异常处理变得更加容易。

原文链接:http://tutorials.jenkov.com/java-exception-handling/fail-safe-exception-handling.html

最新文章

  1. MyBatis Generator 详解 【转来纯为备忘】
  2. Linux Shell 高级编程技巧4----几个常用的shell脚本例子
  3. oracle过程中动态语句实现
  4. missing sdkl in .NET Core 1.0.1 - VS 2015 Tooling Preview 2
  5. 深入PHP EOF(heredoc)用法详解
  6. URAL-1982 Electrification Plan 最小生成树
  7. FOR XML PATH实现小九九
  8. tab group of firefox
  9. 关于Installshield里一些常见问题的解答—艾泽拉斯之海洋女神出品
  10. border-image的拉伸和平铺
  11. HFun.快速开发平台(四)=》自定义列表实例(请求参数的处理)
  12. 转载--关于hdfs
  13. 在Oracle中使用Guid
  14. getParameter和getAttribute区别
  15. PHP大量数据循环时内存耗尽问题的解决方案
  16. How Instagram Feeds Work: Celery and RabbitMQ(转)
  17. Monocular Visual-Inertial Odometry单目视觉惯性里程计
  18. LwIP buffer management, memory configuration options
  19. shell脚本循环处理文件数据
  20. linq 查询的两种方法 (在EF model中实现)

热门文章

  1. A*寻路算法入门(六)
  2. 利用openssl管理证书及SSL编程第2部分:在Windows上编译 openssl
  3. ROS_Kinetic_17 使用V-Rep3.3.1(vrep_ros_bridge)
  4. 《java入门第一季》之UDP协议下的网络编程详解
  5. 1013. Battle Over Cities (25)
  6. javascript语法之number对象和Math对象
  7. Mahout朴素贝叶斯文本分类
  8. 更改EBS R12中forms的模式Servlet/Socket
  9. python标准库:collections和heapq模块
  10. mongodb系列之--分片的原理与配置