博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java7的异常处理新特性-addSuppressed()方法等
阅读量:6439 次
发布时间:2019-06-23

本文共 4523 字,大约阅读时间需要 15 分钟。

开发人员对异常处理的try-catch-finally语句块都比较熟悉。如果在try语句块中抛出了异常,在控制权转移到调用栈上一层代码之前,finally语句块中的语句也会执行。但是finally语句块在执行的过程中,也可能会抛出异常。如果finally语句块也抛出了异常,那么这个异常会往上传递,而之前try语句块中的那个异常就丢失了。如例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package 
test;
 
public 
class 
DisappearedException {
    
public 
void 
show() 
throws 
BaseException {
        
try 
{
            
Integer.parseInt(
"Hello"
);
        
catch 
(NumberFormatException e1) {
            
throw 
new 
BaseException(e1);
        
finally 
{
            
try 
{
                
int 
result = 
2 
0
;
            
catch 
(ArithmeticException e2) {
                
throw 
new 
BaseException(e2);
            
}
        
}
    
}
    
public 
static 
void 
main(String[] args) 
throws 
Exception {
        
DisappearedException d = 
new 
DisappearedException();
        
d.show();
    
}
}
 
class 
BaseException 
extends 
Exception {
    
public 
BaseException(Exception ex){
        
super
(ex);
    
}
    
private 
static 
final 
long 
serialVersionUID = 3987852541476867869L;
}

对这种问题的解决办法一般有两种一种是抛出try语句块中产生的原始异常,忽略在finally语句块中产生的异常。这么做的出发点是try语句块中的异常才是问题的根源。如例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
package 
test;
 
import 
java.io.FileInputStream;
import 
java.io.IOException;
 
public 
class 
ReadFile {
    
public 
static 
void 
main(String[] args) {
        
ReadFile rf = 
new 
ReadFile();
        
try 
{
            
rf.read(
"F:/manifest_provider_loophole.txt"
);
        
catch 
(BaseException2 e) {
            
e.printStackTrace();
        
}
    
}
    
public 
void 
read(String filename) 
throws 
BaseException2 {
        
FileInputStream input = 
null
;
        
IOException readException = 
null
;
        
try 
{
            
input = 
new 
FileInputStream(filename);
        
catch 
(IOException ex) {
            
readException = ex;
        
finally 
{
            
if
(input != 
null
){
                
try 
{
                    
input.close();
                
catch 
(IOException ex2) {
                    
if
(readException == 
null
){
                        
readException = ex2;
                    
}
                
}
            
}
            
if
(readException != 
null
){
                
throw 
new 
BaseException2(readException); 
            
}
        
}
    
}
}
 
class 
BaseException2 
extends 
Exception {
    
private 
static 
final 
long 
serialVersionUID = 5062456327806414216L;
    
public 
BaseException2(Exception ex){
        
super
(ex);
    
}
}

另外一种是把产生的异常都记录下来。这么做的好处是不会丢失任何异常。在java7之前,这种做法需要实现自己的异常类,而在java7中,已经对Throwable类进行了修改以支持这种情况。在java7中为Throwable类增加addSuppressed方法。当一个异常被抛出的时候,可能有其他异常因为该异常而被抑制住,从而无法正常抛出。这时可以通过addSuppressed方法把这些被抑制的方法记录下来。被抑制的异常会出现在抛出的异常的堆栈信息中,也可以通过getSuppressed方法来获取这些异常。这样做的好处是不会丢失任何异常,方便开发人员进行调试。如例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package 
test;
 
import 
java.io.FileInputStream;
import 
java.io.IOException;
 
public 
class 
ReadFile2 {
    
public 
static 
void 
main(String[] args) {
        
ReadFile rf = 
new 
ReadFile();
        
try 
{
            
rf.read(
"F:/manifest_provider_loophole.txt"
);
        
catch 
(BaseException2 e) {
            
e.printStackTrace();
        
}
    
}
    
public 
void 
read(String filename) 
throws 
IOException {
        
FileInputStream input = 
null
;
        
IOException readException = 
null
;
        
try 
{
            
input = 
new 
FileInputStream(filename);
        
catch 
(IOException ex) {
            
readException = ex;
        
finally 
{
            
if
(input != 
null
){
                
try 
{
                    
input.close();
                
catch 
(IOException ex2) {
                    
if
(readException != 
null
){
                        
readException.addSuppressed(ex2);    
//注意这里
                    
}
else
{
                        
readException = ex2;
                    
}
                
}
            
}
            
if
(readException != 
null
){
                
throw 
readException;
            
}
        
}
    
}
}

这种做法的关键在于把finally语句中产生的异常通过 addSuppressed方法加到try语句产生的异常中。

一个catch子句捕获多个异常

在Java7之前的异常处理语法中,一个catch子句只能捕获一类异常。在要处理的异常种类很多时这种限制会很麻烦。每一种异常都需要添加一个 catch子句,而且这些catch子句中的处理逻辑可能都是相同的,从而会造成代码重复。虽然可以在catch子句中通过这些异常的基类来捕获所有的异 常,比如使用Exception作为捕获的类型,但是这要求对这些不同的异常所做的处理是相同的。另外也可能捕获到某些不应该被捕获的非受检查异常。而在 某些情况下,代码重复是不可避免的。比如某个方法可能抛出4种不同的异常,其中有2种异常使用相同的处理方式,另外2种异常的处理方式也相同,但是不同于 前面的2种异常。这势必会在catch子句中包含重复的代码。

对于这种情况,Java7改进了catch子句的语法,允许在其中指定多种异常,每个异常类型之间使用“|”来分隔。如例:

1
2
3
4
5
6
7
8
9
10
11
package 
test;
 
public 
class 
ExceptionHandler {
    
public 
void 
handle(){
        
try 
{
            
//..............
        
catch 
(ExceptionA | ExceptionB ab) { 
        
catch 
(ExceptionC c) {    
        
}
    
}
}

这种新的处理方式使上面提出的问题得到了很好的解决。需要注意的是,在catch子句中声明捕获的这些异常类中,不能出现重复的类型,也不允许其中的某个异常是另外一个异常的子类,否则会出现编译错误。如果在catch子句中声明了多个异常类,那么异常参数的具体类型是所有这些异常类型的最小上界。

关于一个catch子句中的异常类型不能出现其中一个是另外一个的子类的情况,实际上涉及捕获多个异常的内部实现方式。比如:

1
2
3
4
5
public 
void 
testSequence() {
    
try 
{
        
Integer.parseInt(
"Hello"
);
    
catch 
(NumberFormatException | RuntimeException e){}
}

比如上面这段代码,虽然NumberFormatException是RuntimeException的子类,但是这段代码是可以通过编译的。但是,如果把catch子句中两个异常的声明位置调换一下,就会出现在编译错误。如例:

1
2
3
4
5
public 
void 
testSequenceError() {
    
try 
{
        
Integer.parseInt(
"Hello"
);
    
catch 
(RuntimeException | NumberFormatException e) {}
}

原因在于,编译器的做法其实是把捕获多个异常的catch子句转换成了多个catch子句,在每个catch子句中捕获一个异常。上面这段代码相当于:

1
2
3
4
5
6
7
public 
void 
testSequenceError() {
    
try 
{
        
Integer.parseInt(
"Hello"
);
    
catch 
(RuntimeException e) {
    
catch 
(NumberFormatException e) {
    
}
}

来自:http://my.oschina.net/fhd/blog/324484

转载地址:http://wxzwo.baihongyu.com/

你可能感兴趣的文章
彻底理解ThreadLocal
查看>>
Node.js~ioredis处理耗时请求时连接数瀑增
查看>>
企业如何走出自己的CRM非常之道?
查看>>
整合看点: DellEMC的HCI市场如何来看?
查看>>
联合国隐私监督机构:大规模信息监控并非行之有效
查看>>
韩国研制出世界最薄光伏电池:厚度仅为人类头发直径百分之一
查看>>
惠普再“卖身”,软件业务卖给了这家鼻祖级公司
查看>>
软件定义存储的定制化怎么走?
查看>>
“上升”华为碰撞“下降”联想
查看>>
如何基于Spark进行用户画像?
查看>>
光伏发电对系统冲击大 “十三五”电力规划重点增强调峰能力
查看>>
全球19家值得关注的物联网安全初创企业
查看>>
Android下的junit 单元测试
查看>>
这几个在搞低功耗广域网的,才是物联网的黑马
查看>>
主流or消亡?2016年大数据发展将何去何从
查看>>
《大数据分析原理与实践》一一第3章 关联分析模型
查看>>
《挖掘管理价值:企业软件项目管理实战》一2.4 软件设计过程
查看>>
Capybara 2.14.1 发布,Web 应用验收测试框架
查看>>
ExcelJS —— Node 的 Excel 读写扩展模块2
查看>>
《数字短片创作(修订版)》——第一部分 剧本创作 第1章 数字短片创意技法 剧本创作的构思...
查看>>