Java异常

1.异常的概述

  异常指不期而至的各种状况,如:文件找不到、网络连接失败、除0溢出,数组下标越界、非法参数等。异常是一个事件,它发生在程序运行期间,干扰了正常的指令流程。Java通 过API中Throwable类的众多子类描述各种不同的异常。因而,Java异常都是对象,是Throwable子类的实例,描述了出现在一段编码中的错误条件。当条件生成时,错误将引发异常。java程序的执行过程中如出现异常事件,可以生成一个异常类对象,该异常对象封装了异常事件的信息并将被其提交给java运行系统,这个过程成为抛出(throw)异常,当java运行时系统接受到异常对象时,会寻找能处理这一异常的代码并把当前异常对象交给其处理,这一过程成为捕获(catch)异常。设计良好的程序应该在异常发生时提供处理这些错误的方法,是的程序不会因为异常的发生而阻断或产生不可预见的结果。

2.Java异常类结构图

  Java异常类层次结构图:

     

  Throwable:可被抛出的

  Error:系统错误,做自己处理不了的

  Exception:自己可以做处理的,可以catch的

  RuntimeExpetion:经常出的错误(这种错误可以catch,也可以不catch)

  还有一种Exception是必须进行处理的异常,如果不处理,程序就不能编译通过。如IOException、SQLException等以及用户自定义的Exception异常,一般情况下不自定义检查异常。

3.异常的捕获与处理

  当程序中可能出现某种异常时,要么用try-catch语句捕获它,要么用throws子句声明抛出它

  格式1(try-catch):

try {
    //可能抛出异常的语句
} catch ( SomeException1 e ) {
    ......
} catch ( SomeException2 e) {
    ......
} finally {
    ......
}  
  • try代码段包含可能产生异常的代码
  • try代码段后可以跟一个或多个catch代码段
  • 每个catch代码段声明其能处理的一种特定类型的异常并提供处理的方法
  • 当异常发生时,程序会终止当前的流程,根据获取异常的类型去执行相应的catch代码段
  • finally段的代码无论是否发生异常都会在最后进行执行

try{

  • try语句指定了一段代码,该段代码就是一次捕获并处理例外的范围。
  • 在执行过程中该段代码可能会产生并抛出一种或几种类型的异常对象,它后面的catch语句要分别对这些异常做相应的处理
  • 如果没有例外产生,所有的catch代码段都被略过不执行

} catch ( ) {

  • 在catch语句块中是对异常进行处理的代码,每个try语句块可以伴随一个或多个catch语句,用于处理可能产生的不同类型的异常对象
  • 在catch中声明的异常对象(catch(someException e))封装了异常时间发生的信息,在catch语句块中可以使用这个对象的一些方法获取这些信息。
  • 例如:getMessage()方法:用来得到有关异常事件的信息。printStackTrace()方法:用来跟踪异常事件发生时执行堆栈的内容。

}  finally (){

  • finally语句为异常处理提供一个统一的出口,是的在控制流程转到程序的其他部分以前,能够对程序的状态做统一的管理
  • 无论try所指定的程序块中是否抛出例外,finally所指定的代码都要被执行。
  • 通常在finally语句中可以进行资源的清除工作,如:关闭打开的文件,删除临时文件等

  关键词try后的一对大括号将一块可能发生异常的代码包起来,称为监控区域。Java方法在运行过程中出现异常,则创建异常对象。将异常抛出监控区域之外,由Java运行时系统试图寻找匹配的catch子句以捕获异常。若有匹配的catch子句,则运行其异常处理代码,try-catch语句结束。

       匹配的原则是:如果抛出的异常对象属于catch子句的异常类,或者属于该异常类的子类,则认为生成的异常对象与catch块捕获的异常类型相匹配。

  注意:在使用try-catch语句捕获异常时,基类的异常捕获语句不可以写在子类的异常捕获语句上面,不然会报编译的错误

  对于一些自己处理不了的异常或是自己不想去处理的异常,可以直接往外抛异常,这样就可以不用在代码段中加try{}catch{}

  格式2(throws与throw):

public class TestException {
    static void pop() throws NegativeArraySizeException {
        // 定义方法并抛出NegativeArraySizeException异常
        int[] arr = new int[-3]; // 创建数组
    }
 
    public static void main(String[] args) { // 主方法
        try { // try语句处理异常信息
            pop(); // 调用pop()方法
        } catch (NegativeArraySizeException e) {
            System.out.println("pop()方法抛出的异常");// 输出异常信息
        }
    }
 
}
//不加try...catch的另外一种抛异常方法
public class test {
        public static void main(String args[]) throws IOException {
            int i = 0;
            if (i == 0) {
                throw new IOException("出错了");
            }
        }
}

4.自定义异常类

    使用Java内置的异常类可以描述在编程时出现的大部分异常情况。除此之外,用户还可以自定义异常。用户自定义异常类,只需继承Exception类即可。
    在程序中使用自定义异常类,大体可分为以下几个步骤。
    (1)创建自定义异常类,并通过继承java.lang.Exception类。
    (2)在方法中通过throw关键字抛出异常对象。
    (3)如果在当前抛出异常的方法中处理异常,可以使用try-catch语句捕获并处理;否则在方法的声明处通过throws关键字指明要抛出给方法调用者的异常,继续进行下一步操作。
    (4)在出现异常方法的调用者中捕获并处理异常。

  示例:

//创建一个exception类存放自己的exception
public class MyFirstExpection extends Exception {
    private int i;
    public MyFirstExpection (String message,int i) {
        super(message);
        this.i = i;
    }
    public int getI() {
        return i;
    }
}
//测试类
public class TestDemo {
    //定义一个方法
    public void regist(int num) throws MyFirstExpection {
        if(num < 0) {
            throw new MyFirstExpection("不应该为负值", 2);
        }
        System.out.println("注册人数: "+ num);
    }
    //定义另一个方法
    public void manager() {
        try {
            regist(100);
       //regist(-1);
        } catch (MyFirstExpection me) {
            System.out.println("注册失败,出错类型码="+me.getI());
            me.printStackTrace();
        }
        System.out.println("操作结束!");
    }
    //程序入口main方法
    public static void main(String[] args) {
        TestDemo td = new TestDemo();
        td.manager();
    }
}

  测试类的输出结果:

    注册人数: 100
    操作结束!

  更改调用注释掉的regist(-1)方法时,输出结果:  

    注册失败,出错类型码=2
    t1.MyFirstExpection: 不应该为负值
    at t1.TestDemo.regist(DelegationDemo.java:48)
    at t1.TestDemo.manager(DelegationDemo.java:55)
    at t1.DelegationDemo.main(DelegationDemo.java:19)
    操作结束!

  其中t1是包名

  自己可以调试,更改regist方法的传参,自己看输出结果