• 异常


    1. 异常介绍

    1.1. 什么是异常

    异常,就是不正常情况;

    生活中的异常:感冒了;房子漏水;王宝强老婆出事;电脑蓝屏;骑车掉链子;过马路被狗咬了……;

    java中的异常:空指针异常;数组角标越界异常;类型转换异常……

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

    1.2. 异常的作用

    需求:计算两个整数的商;

    1、程序中不可能保证没有问题;即使我们的逻辑很严谨,但是程序一般是要给用户使用的,我们是不能控制用户的输入的;而且有的程序会需要使用第三方的数据,而这第三方的数据也不一定能保证没有问题;所以我们的程序要避免出现问题,是不可能的;

    一个好的程序,不是不会出现问题,而是出现问题后,有预备方案可以解决;异常可以提高程序健壮性;

    2、程序中真的出现问题了,需要有一种机制可以把错误发生的位置、原因等信息记录并显示出来,方便开发者排查错误;

    研究异常,就是为了解决上面提出来的问题;

     

    1.3. java中异常的发生过程

    2. 自定义异常

    问题:JDK自己提供的异常很全面,根据开发中大多数问题,都有相应的异常类,但是我们使用起来是比较麻烦的;

    1、异常类太长,记忆和书写都不方便;

    2、异常类很多,开发者不可能都记下来,使用时就很不方便;

    2.1. 自定义异常

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

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

    class Person//表示人的信息

    {

    private String name;//姓名

    private int age;//年龄

    private String sex;//性别

    public void setName(String name){

    this.name = name;

    }

    public String getName(){

    return name;

    }

    public void setAge(int age){

    if(age > 0 && age < 150){

    this.age = age;

    }else{

    System.out.println("年龄"+age+"不合法!正确的年龄范围是:0150之间!");

    }

    }

    public int getAge(){

    return age;

    }

    public void setSex(String sex){

    this.sex = sex;

    }

    public String getSex(){

    return sex;

    }

    public Person(String name,int age,String sex){

    this.name = name;

    setAge(age);//调用函数进行赋值,可以在这个函数里进行数据有效性检查

    this.sex = sex;

    }

    //重写toString函数,为了可以直接输出对象的各个属性值

    public String toString(){

    return "姓名:"+name+";年龄:"+age+";性别:"+sex;

    }

    }

    class Test

    {

    public static void main(String[] args)

    {

    Person p = new Person("老王",389,"不详");

    System.out.println(p);

    }

    }

    问题:虽然判断出来参数错误了,但是程序仍然可以继续执行,创建了对象,并且给年龄赋了一个不合法的值(默认值);

    实际开发中,如果出现错误数据,是一种异常情况,不应该让程序继续执行下去;

    所以我们可以考虑使用异常来解决;

    结论:在Java中,只有Throwable和它的子类才能作为异常类,对象才能被throw关键字抛出;

    结论:Error表示的是严重的程序自己不应该处理的问题,所以我们自定义的异常不应该继承这个类;

    结论:Exception和它的子类表示的是合理的程序应该自己处理的问题;所以我们自定义异常,应该继承这个类;

    结论:RuntimeException和它的子类表示的异常,可以不需要声明和捕获;

     

    所以如果一个异常类不是必须要声明或捕获,就可以继承RuntimeException类;

    总结自定义异常的一般步骤

    1、要创建一个类,继承RuntimeException或者Exception类;

    2、在这个类中提供一个有参构造函数,接收错误信息;

    3、在这个有参构造函数中将接收到的错误数据通过super语句传递给父类的构造函数;

    2.2. 异常的体系和分类

    java中异常的体系:

    异常的分类:

    编译期异常:

    指的是Exception及其子类(不包括RuntimeException和它的子类)表示的异常;

    特点是:如果在程序中手动抛出这类异常,编译时编译器会检查有没有书写处理代码,如果没有就会报错;

    (也就是说,编译期异常必须处理)

    运行期异常:

    指的是RuntimeException和它的子类表示的异常;

    特点是:如果程序中手动抛出这类异常,不管书写处理代码没有,编译器都不管;

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

    不管是什么异常,真正发生,都是在程序运行的时候;

    如果开发中,有的问题必须要被处理,就应该声明为编译期异常;否则可以声明为运行期异常;

    3. 异常的处理

    现实生活中,有的时候出了问题,可以自己解决,比如玩电脑,突然蓝屏;就可以字节解决,比如重启电脑;

    有的时候,出了问题自己不能解决;比如:走路被车撞断腿了,就不能自己解决;

    3.1. 异常的声明

    如果程序不能自己解决出现的问题,就需要使用throws关键字,将异常的类型声明出去,告诉调用者,这个函数可能会出现问题;

    如果程序中真的出现问题,这个函数就会中断,然后回到调用者那里;

    一个函数声明多个异常:

    如果函数声明的多个异常之间存在继承关系:

    3.2. 异常的捕获

    如果程序中出现的问题可以自己解决,就可以使用try-catch代码块,将可能出错的代码包起来,然后书写处理代码;

    如果程序中真的出现问题,就可以调用处理代码自己解决,函数的调用者是不知道出问题了的;

    这种方法可以捕获多个异常,并且可以针对每个异常作出不同的处理;

    如果要捕获多个异常,而且处理办法都一样,就可以使用另一种写法:

    使用这种方式需要注意:要捕获的多个异常,不能有继承关系;

    一般情况下,如果是因为错误的参数造成的异常,都要声明异常;

    如果是因为自己的逻辑问题造成的异常,一般要捕获;

    4. 异常的细节

    4.1. throwthrows的区别

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

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

    4.2. finally代码块

    一般在捕获异常时,在try-catch代码块后面还可以添加一个finally代码块,作用是,finally块中的代码,一定会被执行

    问题:下列程序的结果是什么?为什么?

    class FinallyDemo

    {

    public static void show(int a){

    try{

    if(a == 1){

    System.out.println("11111");

    throw new Exception();

    }else{

    System.out.println("22222");

    }

    System.out.println("333333333333");

    }catch(Exception e){

    System.out.println("exception");

    return ;

    }finally{

    System.out.println("finally");

    }

    }

    public static void main(String[] args)

    {

    show(1);

    System.out.println("-----------------------------------------");

    show(2);

    }

    }

    结论:不管程序中会不会出现异常,finally代码块中的代码都要执行到!

    4.3. trycatchfinally允许的组合

    可以的组合:

    必须有try代码块;

    三个代码块都不能单独存在;

    try可以和其它两个单独组合,也可以三个一起使用;

    catch可以多次出现;

    因为没有catch捕获异常,所以相当于没有处理异常,所以还要对异常进行声明,否则回编译报错!

     

    4.4. 继承中方法重写的异常

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

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

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

    即子类可不声明,可为父类异常本身,可为父类异常的子类,但不可为父类异常的父类,不可为父类异常的同级异常

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

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

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

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

    5. 异常总结

    异常的概念:

    异常,就是不正常的情况;

    程序中的异常,就是程序出现期望之外的不正常情况;

    异常的作用:

    异常在程序运行中不可避免,合理设置异常和处理代码,可以提高程序的安全型和健壮性;

    异常的体系:

    java中异常也是一种特殊的事物,需要使用类来描述,描述异常信息的类就是异常类;

    java中所有异常类都属于一个继承体系,就是java的异常体系:

    Throwablejava异常体系的最高父类;java中所有可被抛出、捕获或声明的异常类,都要继承这个类或它的子类;

    |----Error:错误,表示程序中严重的不能被JVM处理的问题;遇到这种问题,JVM都会停止运行;

    |----Exception:异常,表示程序中可以被JVM处理的问题;如果程序中抛出该类或它的子类的异常,编译时就会检查有没有书写处理的代码;如果没有写,就会报错;

    |----RuntimeException:表示运行时异常;该类和它的子类表示的异常,在编译期不会检查;

    异常的分类:

    编译期异常:在编译期会被检测有没有处理代码的异常;

    运行时异常:在编译时不会被检测的异常;

    自定义异常的方法:

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

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

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

    异常的处理:

    声明:

    使用关键字:throws,在函数的参数列表后面,大括号前面书写函数可能会抛出的异常;多个异常用逗号分开;

    捕获:

    使用try-catch块包括可能抛出异常的代码。并在catch后面的括号中定义接收抛出的异常对象,在catch后面的大括号里面书写处理代码;

    public class ExceptionDemo2 {

    public static void main(String[] args) {

    // method1();

    // method2();

    // method3();

    // method4();

    // method5();

    }

    //一个异常

    //当没有处理异常时,若出现异常,异常之后的代码就不再执行

    //当处理异常时,若出现异常,会执行catch中的代码,并继续走程序

    private static void method1() {

    int a=10;

    int b=0;

    try {

    System.out.println(a/b);

    } catch (ArithmeticException e) {

    System.out.println("除数不能为0");

    }

    System.out.println("over");

    }

    //两个异常(知识一)

    //一个  try 一个  catch

    //两个异常的代码都可以执行

    private static void method2() {

    int a=10;

    int b=0;

    try {

    System.out.println(a/b);

    } catch (ArithmeticException e) {

    System.out.println("除数不能为0");

    }

    int[] arr={1,2,3,4};

    try {

    System.out.println(arr[5]);

    } catch (ArrayIndexOutOfBoundsException e) {

    System.out.println("索引不存在");

    }

    }

    //两个异常(知识二)

    //一个 try 多个 catch

    //try中代码中,按顺序从上到下执行,遇到异常找到

    //相应的catch就直接结束try catch,后面的异常不再执行,但程序还会继续往下走

    //多个catch的顺序无所谓

    private static void method3() {

    int a=10;

    int b=0;

    int[] arr={1,2,3,4};

    try {

    System.out.println(arr[5]);

    System.out.println(a/b);

    } catch (ArithmeticException e) {

    System.out.println("除数不能为0");

    } catch (ArrayIndexOutOfBoundsException e) {

    System.out.println("索引不存在");

    }

    System.out.println("end");

    }

    //两个异常(知识三)

    //一个 try 多个 catch

    //try中的异常找catch异常时,是按从小到大依次寻找的,若最后还找不到则报错

    private static void method4() {

    int a=10;

    int b=1;

    int[] arr={1,2,3,4};

    try {

    System.out.println(a/b);

    System.out.println(arr[5]);

    } catch (ArithmeticException e) {

    System.out.println("除数不能为0");

    // } catch (ArrayIndexOutOfBoundsException e) {

    // System.out.println("索引不存在");

    }catch (Exception e) {

    System.out.println("大异常");

    }

    }

    //两个异常(知识四)

    //平级的异常谁前谁后无所谓,但如果出现了父子关系,父类异常必须放在后面

    private static void method5() {

    int a=10;

    int b=1;

    int[] arr={1,2,3,4};

    try {

    System.out.println(a/b);

    System.out.println(arr[5]);

    } catch (ArithmeticException e) {

    System.out.println("除数不能为0");

    // }catch (Exception e) {

    // System.out.println("大异常");

    } catch (ArrayIndexOutOfBoundsException e) {

    System.out.println("索引不存在");

    }

    }

    }

  • 相关阅读:
    C# 自定义配置文件
    Mysql JSON字段提取某一个属性值的函数
    linux查看Java线程
    Idea书签管理器的使用
    springboot寻找property的顺序
    SpringBoot的spring-boot-starter有哪些(官方)
    SpringBoot打成jar包的配置方式
    netstat 常用参数总结
    Sentinel统计线程,QPS,RT的方式
    16. kubernetes RBAC
  • 原文地址:https://www.cnblogs.com/dongfangshenhua/p/6800013.html
Copyright © 2020-2023  润新知