10.Java中如何处理异常

1、介绍

1.1 概念

异常,就是不正常情况;程序中出现不符合预期的情况就是异常;

1.2 作用

  • 可以针对程序中出现的问题作出相应处理,提高程序健壮性;
  • 在程序中发生异常的地方通过日志技术将问题记录下来,帮助开发者快速排查错误;

2、异常体系&分类

2.1 体系

  • Throwable:java异常体系的最高父类;java中所有可被抛出、捕获或声明的异常类,都要继承这个类或它的子类;
    • Error:错误,表示程序中严重的不能被JVM处理的问题;遇到这种问题,JVM都会停止运行;
    • Exception:异常,表示程序中可以被JVM处理的问题;如果程序中抛出该类或它的子类的异常,编译时就会检查有没有书写处理的代码;如果没有写,就会报错;
      • RuntimeException:表示运行时异常;该类和它的子类表示的异常,在编译期不会检查;
      • RuntimeException:表示编译期异常;

2.2 分类

  • 编译期异常
    • 概念:指的是Exception及其子类(不包括RuntimeException和它的子类)表示的异常;
    • 特点:如果在程序中使用throw关键字显示的抛出这类异常,编译时编译器会检查有没有书写处理代码,如果没有就会报错;(也就是说,程序中如果抛出这类异常,必须处理)
  • 运行期异常:
    • 概念:指的是RuntimeException和它的子类表示的异常;
    • 特点:如果程序中使用throw关键字显示的抛出这类异常,不管书写处理代码没有,编译时编译器都不管;

编译期异常和运行期异常,指的是编译的时候,是否检查书写了处理代码;

2.3 图解异常分类

3、自定义异常

因为JDK中提供的异常类太多,不方便记忆和使用,所以需要自定义异常

Error表示 程序中严重的不应该处理的问题;

Exception表示程序中应该自己能够处理的问题;

所以,一般自定义异常,可以继承Exception,而不要去继承Error

3.1 自定义异常的步骤:

1.定义一个类,让它继承ExceptionRuntimeException

2.创建一个构造函数,接收一个表示异常信息的参数;

3.调用父类的有参构造函数,将接收的异常信息传递给父类的构造函数;

4.示例:

//需求:创建一个描述人的信息的类,需要对年龄的合法性进行判断;

class WrongAgeException extends RuntimeException{
    WrongAgeException(){}
    WrongAgeException(String errMsg){
         super(errMsg);
    }
}

class Person{
    private int age;
    public void setAge(int age){
        if(age >= 1 && age <= 150){
            this.age = age;
        }else{
            //实际上,如果数据不合法程序就不应该继续向下执行;所以这里应该抛出异常;
            throw new WrongAgeException("输入的年龄"+age+"不合法,正确的范围应该是1(包含)到150(包含)");
        }
    }
    public int getAge(){
        return age;
    }
    public Person(int age){
        setAge(age);//调用函数赋值,可以在创建对象时也对传入的年龄参数进行检验
    }
    //重写toString函数,目的是可以直接输出这个对象的属性值
    public String toString(){
        return "年龄:"+age;
    }
}

//测试
class Test{
    public static void main(String[] args) {
        Person p = new Person(-10);	
        System.out.println(p);
        p.setAge(-2);
        System.out.println(p);
    }
}

4、异常的处理

4.1 异常的声明

如果程序不能自己解决出现的问题,就可以使用throws关键字,在函数的参数列表后面、函数体大括号前面将异常的类型声明出去,目的时告诉调用者,这个函数执行时有可能会出现什么问题;这种处理方法就叫做异常的声明;

自己不处理,告诉调用者,自己可能出什么问题,真出了问题,就将问题抛给调用者;

4.2 异常的捕获

如果程序中出现的问题可以自己解决,就可以使用try-catch代码块,将可能出错的代码包起来,然后书写处理代码;这种处理方式叫做异常的捕获;

自己直接将问题解决,不惊动调用者;

看具体情况;一般如果问题是因为传入的参数不合法造成的,就应该使用异常的声明;否则应该使用捕获;

5、异常部分细节

5.1 throwthrows的区别

throw:用来在函数里面抛出异常对象;

throws:用来声明函数会抛出异常;

5.2 finally代码块

一般在捕获异常时,在try-catch代码块后面还可以添加一个finally代码块,

作用是:在finally块中的代码,一定会被执行;

一般再开发中,有些工作一定要执行的,都会放到finally代码块中完成;

5.3 trycatchfinally允许的组合

  • 必须有try代码块;
  • 三个代码块都不能单独存在;
  • ry可以和其它两个单独组合,也可以三个一起使用;
  • catch可以多次出现;

5.4 继承中方法重写的异常

子类重写父类函数,不能比父类函数声明更多编译期异常;

父类方法没有声明异常,子类重写的方法不能声明编译时异常

父类方法声明了一个编译异常,子类重写的方法只能声明这个异常或它的子异常

父类方法声明了多个编译异常,子类重写的方法只能声明这些异常的子集或子集的子类