Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 719|回复: 0

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

[复制链接]
  • TA的每日心情
    奋斗
    8 小时前
  • 签到天数: 793 天

    [LV.10]以坛为家III

    2049

    主题

    2107

    帖子

    72万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    723458
    发表于 2021-5-25 09:48:55 | 显示全部楼层 |阅读模式

    开发人员对异常处理的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

    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-9-18 23:23 , Processed in 0.058735 second(s), 27 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表