Java7的异常处理新特性-addSuppressed()方法等

Java7的异常处理新特性-addSuppressed()方法等

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

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语句块中的异常才是问题的根源。如例:

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方法来获取这些异常。这样做的好处是不会丢失任何异常,方便开发人员进行调试。如例:

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子句的语法,允许在其中指定多种异常,每个异常类型之间使用“|”来分隔。如例:

package test;



public class ExceptionHandler {

    public void handle(){

        try {

            //..............

        } catch (ExceptionA | ExceptionB ab) { 

        } catch (ExceptionC c) {    

        }

    }

}

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

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

public void testSequence() {

    try {

        Integer.parseInt("Hello");

    } catch (NumberFormatException | RuntimeException e){}

}

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

public void testSequenceError() {

    try {

        Integer.parseInt("Hello");

    } catch (RuntimeException | NumberFormatException e) {}

}

 

 

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

public void testSequenceError() {

    try {

        Integer.parseInt("Hello");

    } catch (RuntimeException e) {

    } catch (NumberFormatException e) {

    }

}

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值