一、什么是异常

   定义

异常(Throwable),是代码运行中的不符合预期的特殊情况

  异常的分类及特点

1.分类   

①异常可以分为错误(Error)和异常(Exception)

②错误通常是因为语法逻辑或者硬件问题导致

③异常是程序在运行和配置中产生的问题

④异常可以再细分为受检异常(编译就报错)非受检异常(编译时不报错,运行时报错)

2.异常的必要性

在代码中存在各种各样的不可预期情况,异常可以起到维持程序的稳定性作用

二、常见的异常

1.算术异常(ArithmeticException )

        通常是因为运算逻辑有误,例如0作为被除数

2.数组索引越界异常(ArrayIndexOutOfBoundsException )

        通常因为使用超出数组长度的元素,例如一个数组的长度为2,然后给数组下标为3的元素赋值时就会报数组越界

3.空指针异常

        调用一个空对象的方法,例如调用一个值为null的对象的quals方法与一个其他的值进行比较(所以使用equals方法比较String值的时候通常把变量写在后面的括号内,明确的值写在前面)

4.类型转换异常

         例如子类强转成父类       

三、解决异常

1.捕获异常

捕获异常之后的代码语句正常运行,捕获异常通常用在自己能解决异常,并且需要后续代码正常运行的情况下

/*
语法格式
try{
    可能出现异常的代码
}catch(异常类型 异常名){
    处理代码
}
*/


int[] nums=new int[2];
try{
    nums[3]=15;//超出数组定义长度,属于数组索引越界()
}catch(ArrayIndexOutOfBoundsException e){
    System.err.println("数组索引异常")//err设定输出字体颜色为红色
}

System.out.println("捕获异常后")

2.当捕获多个异常时

public static void main(String[] args){
    test(null);
    test();
}

public static void test(String str){
    try{
        System.err.println(str.equals(""));//如果传入参数为null,则爆空指针异常
        int num=12/0;//算术异常
        System.out.println("try代码块中")

/*如果try中有多个异常,可以在catch中使用|写多个异常,不能用||,或者可以直接用Exception涵盖所有异常*/
        }catch(NullPointerException  | ArithmeticException e){
            e.printStackTrace//输出异常信息
            System.out.println("catch代码块中")
        }
System.out.println("结果");
}

最后结果输出:

空指针异常报错
catch代码块中
最后
true
算术运算报错
catch代码块中
最后

步骤解析

①第一次调用方法的时候传入参数为null,try中第一行代码爆空指针异常

②由于第一行报错了,try代码块中在报错代码后的其他代码不执行,跳到catch代码块中继续执行

③第二次调用方法传入参数不为空,执行到第二行报算术异常,第三行的输出语句仍然不执行,继续跳到catch代码块中执行其他代码

由此可以得知,在捕获多个异常时,try代码块中,从出现异常的语句开始,知道try代码块结束之间的代码都不会再执行,catch代码块已经外部后面的代码不受影响

四、finally(注意不是final)

1.作用

        保证finally代码块中的代码一定会被执行

2.如何使用

        写在catch代码块之后,当没有catch代码块时可以直接写在try代码块之后

3.语法格式

try{
}catch(){
}finally{
}

五、声明异常类型(throws,可以一次声明多个异常类型)

1.定义

        声明可能存在的异常,由上层解决,如果上层无法解决将继续向上层声明出来,直至结尾

声明异常,如果没有捕获的话,结果还是会报错停止后续代码的运行

2.作用

        为了能够让上层捕获异常,如果不抛出异常,一旦程序出现错误上层不知道是哪个部位出错,只知道有一个部位出错,不知道用什么办法解决。这是如果抛出了异常,上层代码可以知道问题代码所在,及时处理避免程序崩溃

3.案例

public class Demo1{
    /*3.抛出到这里无法继续向上抛出了,编译报错程序结束运行,异常代码之后的其他代码不运行,即使后面又finally代码块也不会再继续执行了*/

    public static void main(String[] args)throws Exception{
        //2.调用方要处理异常,如果不处理的话继续向上抛出
        total(4);
    //4.不会运行后续代码,程序已经被结束了
    try{
           int num=5/0;
       }catch(ArithmeticException e){
           //System.out.println("算术异常");
       }finally{
           System.out.println("finally输出");
       }
    }

//1.throws Exception将可能出现的异常向上抛出    
    public static double total(int num)throws Exception{
            return num/0;   //算术异常
    }
}

六、抛出异常对象(只能抛出单个异常对象)

1.定义

        在方法内通过手动创建对象抛出异常

2.语法格式        

        throw new 异常类型

3.案例

        

public static void main(String[] args) {
        int num=0;
        total(num);
    }

    public static void total(int num){
        int num2=5/num;//传入参数为0时,算术异常
        //throw new 异常类型();
        throw new ArithmeticException("除数不能为0");
    }

七、自定义异常

1.语法格式

public class  (类名+Exception) extends Exception(){
              //无参构造方法
                public (类名+Exception)(){
                super();
}
                //添加一个带异常信息的有参构造方法
                public (类名+Exception)(){
                super();
        }      
}

2.注意点

  • 自定义异常的类名通常末尾加上Exception表明这是异常
  • 自定义异常必须要继承Exception或者RuntimeException
  • 继承自Exception说明是一个编译期间就会报错的异常,编译期异常必须处理try或者throws
  • 继承自RuntimeException的异常就是一个运行期异常,无需处理,交给虚拟机处理,中断处理。
  • 通过向构造方法中默认存在的父类构造方法super()传入参数,输出异常信息