曹阳的博客 仅用于学习和分享

Java异常机制

2019-10-31

核心类库D4: 异常机制(重点、简单)

1.1 基本概念

  1. 异常就是”不正常”的含义,在Java语言中主要指程序运行阶段发生的错误。
  2. java.lang.Throwable类是所有错误(Error)和异常(Exception)的超类。
  3. 其中Error主要用于描述比较严重无法通过编码解决的错误,如:JVM挂了。
  4. 其中Exception类主要用于描述比较轻微可以编码解决的错误,如:0作为除数。

1.2 基本分类

  1. java.lang.Exception类是所有异常的超类,主要子类有两大类:
    • RuntimeException - 运行时异常,也叫作非检测性异常。
    • IOException和其它异常 - 其它异常,也叫作检测性异常。
    • 所谓检测性异常就是指在编译阶段能够被编译器检测出来的异常
  2. 其中RuntimeException类的主要子类:
    • ArithmeticException - 算术异常
      if(ib != 0)
    • ArrayIndexOutOfBoundsException - 数组下标越界异常
      if(pos >= 0 && pos < arr.length)
    • NullPointerException - 空指针异常
      if(null != str1)
    • ClassCastException - 类型转换异常
      if(ex instanceof IOException)
    • NumberFormatException - 数字格式异常
      if(str2.matches("\\d+"))
  3. 注意:
    • 当程序执行过程中发生异常又没有手动处理时,该异常由Java虚拟机采用默认方式处理,而默认处理方式就是打印:异常名称、异常原因、异常发生的位置,然后终止程序
    • 数组名后面length是特征,不用加小括号
    • String类后面length是方法,要加小括号

1.3 异常的避免

  1. 在以后的开发中尽量多使用if条件判断来避免异常的发生

1.4 异常的捕获

  1. 语法格式
    try {    
     // 编写所有可能发生异常的语句;    
    }    
    catch(异常类型 变量名) {    
     // 编写针对该类异常处理的语句;    
    }    
    ...    
    finally {    
     // 编写无论是否发生异常都应该执行的语句;    
    }    
    
  2. 注意事项
    • 当需要编写多个catch分支时,切记小类型的异常处理放在大类型的上面(如catch(Exception e)放在上面下面就不用写了)
    • 懒人的写法: catch(Exception e) {e.printStackTrace}
    • finally无论是否发生异常都会执行,主要用于进行善后处理,如:关闭打开的文件等。
    • 处理异常和不处理异常的区别:程序是否会继续向下执行
  3. 执行流程
    try{    
     a;    
     b; // 可能发生异常的语句    
     c;    
    }    
    catch(...) {    
     d;    
    }    
    finally{    
     e;    
    }    
    //若没有发生异常时的执行流程: a  b  c   e    
    //若发生异常时的执行流程:a  b  d  e    
    
  4. final/finally/finalize()的区别
    • final关键字:final修饰的类不能被继承,final修饰的方法不能被重写可以被继承,final修饰的成员变量必须初始化且不能被修改
    • finally关键字:在异常捕获过程中做善后处理
    • finalize()方法:当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法

1.5 异常的抛出

  1. 基本概念
    在某些特殊场合中发生异常无法捕获或者不便于捕获处理时,则可以将该异常转移给该方法的调用者,这个过程就叫异常的抛出。

  2. 语法格式
    访问权限 返回值类型 方法名称(形参列表) throws 异常类型1, 异常类型2, ... {}    
        
    public void show() throws IOException {}    
    
  3. 方法重写的原则
    • 要求方法名相同、参数列表相同、返回值类型相同,jdk1.5开始可以返回子类类型
    • 要求访问权限不能变小,可以相同或者变大
    • 要求不能抛出更大的异常
  4. 注意:
    子类重写的方法不可以抛出更大的异常、平级不一样的异常,但可以抛出一样的异常、更小的异常以及不抛出异常。

1.6 自定义异常

  1. 基本概念
    虽然Java官方提供了大量的异常类,但没有提供针对年龄不合理等情况的异常,为了使用这种具备针对性的异常,就需要程序员自定义异常类。

  2. 实现流程
    • 自定义xxxException类继承Exception类或者其子类。
    • 提供两个版本的构造方法,一个是无参构造方法,另一个是字符串作为参数的构造
  3. 异常的产生
    throw new 异常类型();    
        
    throw new NullPointerException();    
    
  4. 例子
    1.自定义年龄异常  
    public class AgeException extends Exception {  
     private static final long serialVersionUID = 1L;  
     public AgeException() {  
     }  
     public AgeException(String msg) {  
         super(msg); // 调用父类的有参构造方法  
     }  
    2.自定义异常成员方法  
    public void setAge(int age) throws AgeException {  
     if(age > 0 && age < 150) {  
         this.age = age;  
     } else {  
         //System.out.println("年龄不合理!!!");  
         // 产生异常来表达年龄不合理的抗议  
         //throw new NullPointerException();  
         throw new AgeException("年龄不合理!!!");  
     }  
     }  
    
  5. throw和throws的区别
    • throws写在方法的参数列表后面,后跟类型,可以跟好多类型
    • throw写在方法体里面,后跟对象,只能跟一个对象

1.7 异常的总结

异常机制的总结.png

1.8 使用场景

  1. 使用抛出异常的情景主要有:

    1. 异常必须由容器来处理,异常时容器做出不同处理的依据和触发;

      例如:有事务处理的方法中,事务相关的逻辑必须抛出异常,而不能捕获异常,否则会导致事务不回滚。

    2. 本地方法不知道如何处理,只有调用方才可能知道如何处理异常;

      例如:一些底层的方法,其可能出现多种异常,且调用方可能根据不同的异常做出不同的处理,只能抛出异常,而且必须是具体的异常类型,而不能是笼统的Exception类型。

  2. 使用try/catch捕获异常的情景主要有:

    1. 程序块中语句可能的异常不能引起其他逻辑中断;

      例如:缓存逻辑不能影响正常的逻辑运行,故缓存逻辑应该放在try/catch块中。

    2. 必须对异常进行处理,否则会降低用户使用体验。

      例如:异常到了Controller层,若不处理则会返回404或500错误页面,因此,必须使用try/catch处理各种异常。


上一篇 Java集合

下一篇 Vue.js基础

Content