java中的异常以及处理

概述

1.异常是一个体系,具有自己的体系结构。
2.用于表达程序中特殊情况的一种手段

这句话是什么意思呢?
1.在程序中,可能会出现某些情况,例如给用户的年龄赋值的时候,可能会错误录入,(比如负数,符号等)出现这种情况是不符合生活的正常状态的时候就认为是一个异常,
2.碰到异常情况之后,就可以使用异常对象的方式,描述异常信息。
可以将异常抛出,实现程序的结束或者跳转

3.是用于处理特殊情况的一种机制。

异常体系

Throwable             //异常体系的顶级父类
Error                 //正常程序,不应该捕获处理,严重问题
Exception             //异常(例外),正常程序,应该试图捕获处理,轻微的问题
    RuntimeException  //运行时异常

jvm默认处理异常的方式

1.当某个方法出现异常情况时,会将异常封装成一个异常对象。
2.异常对象抛出给调用者,一层一层往上抛,最终到达main方法,主方法也没有办法处理,就抛出给jvm虚拟机
3.jvm虚拟机有没有得到指令处理异常,只能将异常的信息通过标准错误流(System.err)打印到控制台,结束自己。

示例代码:

package Exception;

import java.util.Scanner;

public class Demo1_异常的处理 {
    public static void main(String[] args) {
        getNum(new Scanner(System.in).nextInt());//当输入0的时候会出现异常
    }

    private static void getNum(int i){
        System.out.println(10 / i);
    }

}

在这里插入图片描述
这里报了一个异常叫做

ArithmeticException: / by zero    算数异常 0不能作为除数。

在我们平时书写代码的时候也会经常的遇见这些异常,下面就来说一下异常的处理方式。

手动处理异常

概述:
1.通过写代码来对异常的处理方案做干预。
(一般如果在代码中出现异常了,没有合适的方法处理会导致代码向上抛出异常,一层一层最后到jvm虚拟机来在控制台抛出异常信息,我们要做的就是对这个异常进行捕获和干预)
2.分类:
对异常进行声明(说明白了会出问题,你要么想办法处理,要么别怪我)
对异常进行捕获解决
3.解决的办法
try…catch
try…catch…finally
try…finally

捕获解决的第一种格式:
1.格式:

try {
 	 	可能出现异常的代码
} catch (可能出现的异常类型 异常的变量名称) {
 	针对该异常类型的处理办法
}

2.说明:

1.try ,尝试,可能会失败,用于对异常的检测。
2.catch:抓住,捕获
小括号,捕获定义的这种异常类型的异常,变量名称表示一个异常对象的引用。
大括号,针对这种异常的处理方案。
3.执行流程:
(1)执行try语句。
(2)如果没有异常,当try执行完毕时就算完成了。
(3)如果在执行try语句的时候,出现了异常,就和catch中声明的异常进行匹配(catch括号里面的),如果匹配成功,就执行针对这种异常的处理方案;如果没有匹配成功,就按照jvm默认的处理方式来处理。

示例代码:

package Exception;

import java.util.Scanner;

public class Demo2_异常的处理的第一种格式 {
    public static void main(String[] args) {

        try {
            getNum(new Scanner(System.in).nextInt());//当输入0的时候会出现异常
        } catch (ArithmeticException e) {
            System.out.println("除数不能为0");
        }
    }

    private static void getNum(int i) {
        System.out.println(10 / i);
    }

}

在这里插入图片描述

捕获解决的第一种格式的多种异常情况

1、一段代码在一次运行过程中,只能发生一个异常,但是可能发生的异常种类有很多
2、针对多种可能出现的意外情况,就需要准备针对每种异常情况做方案
3、格式:

	try {
  	 	可能出现异常的代码
} catch (异常类型1 异常名称1) {
   	针对异常类型1的处理方案
} catch (异常类型2 异常名称2) {
 	针对异常类型2的处理方案
}
...
} catch (异常类型n 异常名称n) {
 	针对异常类型n的处理方案
}

4、执行流程:

1、执行try中的内容,如果执行成功,就当前语句块就结束了
2、如果在try中发生了异常,就跳转到catch块中,从上到下依次匹配这些异常类型,匹配到哪个类型,就执行哪个类型对应的处理方案
3、当某种方案执行完成,整个try…catch就算执行完了,并且catch执行完之后,就相当于法异常没有发生,后续代码继续执行

5、注意事项:

1、如果在多个catch块中,可能出现的异常类型有子父类的关系,必须子类异常在上面,父类异常在下面
2、如果有多种异常,需要有相同的处理方案,可以将多种异常进行“逻辑或”运算,具体格式:(jdk1.7出现)

 	catch(可能出现的异常类型1 | 可能出现的异常类型2 异常对象名称) {
  	 	两种异常出现之后的处理方案
}

代码示例:

package Exception;

import java.util.InputMismatchException;
import java.util.Scanner;

public class Demo2_异常的处理的第一种格式 {
    public static void main(String[] args) {

        while (true) {
            try {
                System.out.println("输入除数");
                getNum(new Scanner(System.in).nextInt());//当输入0的时候会出现异常,和输入不匹配异常。


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

                System.out.println(arr2[20]);//下标越界异常。
            } catch (ArithmeticException e) {
                System.out.println("除数不能为0");
            } catch (InputMismatchException e) {
                System.out.println("输入不匹配");
            } catch (ArrayIndexOutOfBoundsException e) {
                System.out.println("下标越界异常");
            }
        }
    }

    private static void getNum(int i) {
        System.out.println(10 / i);
    }

}

在这里插入图片描述

捕获异常的第二种方式

1、格式:

try {
 	可能出现异常的代码
} catch (可能出现的异常类型 异常名称) {
 	这种异常的处理方案
} finally {
 	一定会执行的代码
}

2、finally:

1、没有发生异常,finally会执行
2、发生了可以捕获的异常,finally会执行
3、发生了无法捕获的异常,finally也会执行

3、finally的作用
一般用于关闭资源
示例代码:

package Exception;

import java.util.Scanner;

public class Demo2_异常的处理的第一种格式 {
    public static void main(String[] args) {

        while (true) {
            try {
                System.out.println("输入除数");
                getNum(new Scanner(System.in).nextInt());//当输入0的时候会出现异常,和输入不匹配异常。
            } catch (ArithmeticException e) {
                System.out.println("除数不能为0");
            } finally {
                System.out.println("必须执行的代码");
            }
        }
    }

    private static void getNum(int i) {
        System.out.println(10 / i);
    }

}

在这里插入图片描述

捕获解决异常的第三种格式

1、说明:
第三种格式只能检测异常,不能捕获和解决异常
2、格式:

 	try {
 	 	可能出现异常的代码
} finally {
 	一定要执行的代码
}

3、作用:
将try中的代码和finally中的代码,分离开,不会因为try中代码的执行失败,影响到finally中的代码的执行机会

这个和try catch finally差不多,这里就不在写代码示例了。

编译时异常和运行时异常

1、强调:

1、无论是编译时异常,还是运行时异常,都是只能发生在运行阶段的异常
2、编译阶段只能有“编译成功”(会出现.class的字节码文件),“编译失败”(无法生成.class的字节码文件)
3、编译失败出现的报错信息(javac.exe编译java源代码时,将错误了打印)

2、区别:

1、继承体系区别
编译时异常,都是Exception或者Exception的子类(RuntimeException除外)
运行时异常,都是RuntimeException以及RuntimeException的子类
2、处理方式区别
运行时异常,在编译阶段不强制要求给出解决方案的异常,可以在编译阶段,认为将来没有异常发生,因此可以对该异常不做任何处理,还可以使用非异常处理的方式,对异常进行避免

编译时异常,在编译阶段强制要求给出出现异常之后的解决方案,如果没有给出,就编译报错,不允许运行。没有办法通过非异常处理的手段进行避免异常。

示例代码:

package Exception;

import java.io.FileInputStream;
import java.util.Scanner;

public class Demo3_编译时和运行时异常 {

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int num = sc.nextInt();

        if (num != 0) {
            int result = 10 / num;
            System.out.println(result);
        }

        FileInputStream fis = new FileInputStream("a.txt");//这一句就是编译时异常,不解决无法编译成功。
    }
  

在这里插入图片描述

Throwable中的常用方法

1、说明:
在整个异常体系中,几乎所有的成员方法都定义在Throwable整个顶层父类中,在各种子类中,没有特有的成员方法;构造方法也是都在访问Throwable中的构造方法
2、构造方法:用于将异常情况封装成对象

 	Throwable()
 	 	创建一个没有描述的异常对象
 	Throwable(String message)
 	 	创建一个带有消息描述的异常对象
 	Throwable(Throwable cause)
 	 	创建一个带有原因异常对象的异常对象

3、成员方法:所有的异常都可以调用以下方法

getMessage()
 	 	获取异常对象中的详细消息字符串
 	toString()
 	 	获取异常对象中的简短描述
 	getCause()
 	 	获取异常对象中的原因异常对象
 	printStackTrace()
 	 	打印当前异常对象的调用栈轨迹
 	 	栈轨迹:调用的轨迹,可以很清晰的表示出异常出现和抛出的路径,有了这个信息,		可以查找出具体出现问题的地方

代码示例:

package Exception;

import java.util.Scanner;

public class Demo2_异常的处理的第一种格式 {
    public static void main(String[] args) {


            try {
                System.out.println("输入除数");
                getNum(new Scanner(System.in).nextInt());//当输入0的时候会出现异常,和输入不匹配异常。
            } catch (ArithmeticException e) {
                System.out.println("除数不能为0");
                System.out.println(e.getMessage());
                System.out.println(e.toString());
                System.out.println(e.getCause());
            }
        }


    private static void getNum(int i) {
        System.out.println(10 / i);
    }

}

在这里插入图片描述

throw关键字

1、作用:
将一个异常对象抛出,实现程序的跳转或者结束
2、使用场景
当程序运行到了,程序员认为不正常的情况时(不符合生活的正常状态、不符合当前业务逻辑的时候),就不需要让程序继续按照正常的逻辑运行下去,就在这个条件下抛出一个异常对象
3、注意事项:

1、如果抛出的是一个运行时异常,那么在编译阶段就相当于没有异常
2、如果抛出的是一个编译时异常,那么就需要对该异常进行处理(声明或者解决

代码示例:

package Exception;

public class Demo4_throw关键字 {
    public static void main(String[] args) {
        getNum(0);
        
        
    }


    private static void getNum(int i) {
        if (i == 0){
            throw new RuntimeException("0不能作为除数");
        }else{
            System.out.println(10 / i);
        }
    }
}

在这里插入图片描述
这次报的是运行时异常而不是算术异常。

throws关键字

1、作用:
用于给一个方法声明可能出现的异常类型
2、格式:

修饰符 返回值类型 方法名称(参数列表) throws 异常类型1, 异常类型2... {

}

3、说明:

1、用于表达可能出现的异常类型
2、即使没有出现这种异常,也可以声明

4、注意事项:

1、运行时异常不需要声明,声明了也相当于没声明
2、尽量声明小的、少的异常

代码示例:

package Exception;

import java.io.FileInputStream;
import java.io.FileNotFoundException;

public class Demo5_throws关键字 {
    public static void main(String[] args) throws FileNotFoundException {
        FileInputStream fis = new FileInputStream("a.txt");
    }
}

自定义异常

1、jdk中提供了很多的异常类型,都没有什么特有的方法
2、为什么要提供那么多的异常类型?

1、方便辨别出现的异常情况,代码中可能出现各种例外情况,如果有不同类型的异常对象,就可以非常快速的根据异常类型,定位出现异常情况的位置和原因
 	2、可以根据不同的异常类型,判断出不同的异常情况,方便在多个catch块中,做不同的处理方案

3、为什么要自定义异常?
在自己公司、当前项目中,可能出现一些特有的例外情况,没有被定义在jdk中,就需要自己定义这个类型,方便处理和辨认。
3、自定义异常的步骤:

1、定义一个类,以Exception结尾
2、继承异常类型
如果是编译时异常,就继承Exception
如果是运行时异常,就继承RuntimeException
3、自己写出构造方法
Alt + shift + s c

示例代码:

代码1:

package Exception;

public class Person {
    private int age;
    private String name;

    public Person(int age, String name) {
        this.age = age;
        this.name = name;
    }

    public int getAge() {
        return age;
    }
   public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(int age) {
       if(age < 0){
           throw new IllegalAgeException("年龄非法: " + age);//抛出一个自定义类型的异常,也是我觉得不符合常理的情况
       }else {
           this.age = age;
       }
    }

 

    @Override
    public String toString() {
        return "Person{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
}

代码2:

package Exception;

public class IllegalAgeException extends RuntimeException{
    public IllegalAgeException() {
    }

    public IllegalAgeException(String message) {
        super(message);
    }
}
//自定义的异常类型

代码3:

//测试类

package Exception;

public class Demo5_自定义异常 {
    public static void main(String[] args) {
        Person p = new Person(12, "小明");
        try {
            p.setAge(-2);
        } catch (IllegalAgeException e) {
            System.out.println(e.getMessage());
        }

        System.out.println(p);
    }
}

在这里插入图片描述

好了异常的不分就暂时介绍到这里。

感谢能看到这里,如果喜欢请点个赞谢谢

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值