JavaSE学习之try+catch的异常处理

一、什么是异常?

  • 异常是在程序中导致程序中断运行的一种指令流
  • 异常的产生:
    1. 发生了异常(JVM根据异常的情况,创建了一个异常的对象,包含了异常信息);
    2. main未自动处理,自动将异常抛给了main的调用者JVM;
    3. JVM对异常信息进行了响应(将异常信息显示到控制台,并进行中断程序处理)
  • 现有如下代码块:
    public static void main(String[] args) {
            int a = 10;
            int b = 0;
            System.out.println("123456789");
            System.out.println(a/b);
    }

那运行结果是什么?
在这里插入图片描述
显然,代码出现异常了。
既然异常出现了,我们该怎么解决它,怎么处理它才是最好的办法?

如果要想对异常进行处理,则必须采用标准的处理格式,处理格式语法如下(本文使用是 try+catch进行异常处理):

try{
		//有可能发生异常的代码块
	}catch(异常类型1 对象名1){
		//异常处理操作
	}catch(异常类型2 对象名2){
		//异常处理操作
	}...
	finally{
		//异常的统一出口
	}

那么 try+catch 处理异常的流程是怎样的呢?
流程如下:

  • 一旦产生异常,则系统会自动产生一个异常类的实例化对象。
  • 那么,此时如果异常发生在try语句,则会自动找到匹配的catch语句执行,如果没有在try语句中,则会将异常抛出.
  • 所有的catch根据方法的参数匹配异常类的实例化对象,如果匹配成功,则表示由此catch进行处理。

二、异常的体系结构

  • 异常指的是Exception , Exception类, 在Java中存在一个父类Throwable(可能的抛出) Throwable存在两个子类:
  • Error:表示的是错误,是JVM发出的错误操作,只能尽量避免,无法用代码处理。
  • Exception:一般表示所有程序中的错误,所以一般在程序中将进行try…catch的处理。
    在这里插入图片描述
    从上面的图中可以看出,异常可以分为两个大类:
  • 受检异常:当系统检测到代码段可能出问题时,会自动飘红提示程序员处理异常(将异常抛出或做其他处理)
  • 非受检异常(RuntimeException):当代码段可能会出现异常时,系统不会自动检测,只是在程序运行是进行中断程序运行处理,并将异常输出在控制台上。

三、异常的处理

异常的捕获:
Java提供了try(尝试)、catch(捕捉)、finally(最终)这三个关键字来处理异常。在处理各种异常时,需要用到对应的异常类,指的是由程序抛出的对象所属的类。

示例代码如下:

public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        System.out.println("请输入一个数字:");
        int m = input.nextInt();
        System.out.println("请在输入一个数字:");
        int n = input.nextInt();

        try {
            System.out.println(m / n);
            System.out.println("处理完毕!");
        }catch (ArithmeticException e){
            System.out.println("除数不能为0");
        }
    }

可以看出,在异常捕捉的过程中要进行两个判断,第一是try程序块是否有异常产生,第二是产生的异常是否和catch()括号内想要捕捉的异常相同。

那么,如果出现的异常不止一个时,我们又该如何?事实上我们可以在一个 try 语句后跟上多个异常处理 catch 语句,来处理多种不同类型的异常,这就是多异常处理。

  • 示例代码一:
public class Demo01 {
    /**
     * 处理多异常格式--01
     * @param args
     */
    public static void main(String[] args) {
        try {
            Scanner input = new Scanner(System.in);
            System.out.println("请输入一个数字:");
            int m = input.nextInt();
            System.out.println("请在输入一个数字:");
            int n = input.nextInt();
            System.out.println(m / n);
            System.out.println("处理完毕!");
        }catch (ArithmeticException e){
            System.out.println("除数不能为0");
        }catch (InputMismatchException e){
            System.out.println("输入的数据格式必须为数字!");
        }
    }
}

这样,我们就能够针对不同的异常对其进行处理啦~

除此之外,其实我们还有其他多种的格式处理多异常:

  • 示例代码二:
public class Demo02 {
    /**
     * java处理多异常--02(合并处理,了解即可)
     * @param args
     */
    public static void main(String[] args) {
        try {
            Scanner input = new Scanner(System.in);
            System.out.println("请输入一个数字:");
            int m = input.nextInt();
            System.out.println("请在输入一个数字:");
            int n = input.nextInt();
            System.out.println(m / n);
            System.out.println("处理完毕!");
        }catch (ArithmeticException|InputMismatchException e){
            System.out.println("输入有误,请检查!");
        }
    }
}

通过Java的逻辑表达式 “或”("|")将两个异常做统一的处理。

  • 示例代码三:
public class Demo03 {
    /**
     * java处理多异常--03  常用
     * @param args
     */
    public static void main(String[] args) {
        try {
            Scanner input = new Scanner(System.in);
            System.out.println("请输入一个数字:");
            int m = input.nextInt();
            System.out.println("请在输入一个数字:");
            int n = input.nextInt();
            System.out.println(m / n);
            System.out.println("处理完毕!");
        }catch (RuntimeException e){
            System.out.println("输入有误,请检查!");
        }
    }

可以看到,这样操作等于是把所有的非受检异常做了统一的处理。

  • 示例代码四:
    public static void main(String[] args) {
        try{
            int a = 10;
            int b = 0;
            System.out.println(a/b);
        }catch (Exception e){
            System.out.println("出现了异常,退出!");
        }
    }

上面的这种写法更加直接了当了哈,直接一个catch()将所有的异常全部统一处理,这样做虽然节省了时间和精力,但是它的针对性不强,无法针对某个异常来做相应的处理。(非必要的话不推荐)

四、Finally关键字

在进行异常的处理之后,在异常的处理格式中还有一个finally语句,那么此语句将作为异常的统一出口,不管是否产生了异常,最终都要执行此段代码。

  • 示例代码:
    public static void main(String[] args) {
        try{
            int a = 10;
            int b = 0;
            System.out.println(a/b);
        }catch (Exception e){
            System.out.println("出现了异常,退出!");
        }finally {
            System.out.println("123456");
        }
    }

在这里插入图片描述
除此之外熬,finally关键字还有其他特性——在return准备返回值的时候执行。话不多说,上代码:

  • 示例代码一:
public class testdemo {
    public static void main(String[] args) {
        Person p = demo();
        System.out.println(p.age);
    }
    public static Person demo(){
        Person p = new Person();
        try{
            p.age = 18;
            return p;
        }catch (Exception e){
            return null;
        }finally {
            p.age = 28;
        }
    }
    static class Person{
        int age;
    }
}

那思考一下,这种情况下,我们控制台输出的内容是什么?
在这里插入图片描述
输出28,没错。那为什么呢?

这个得用堆和栈的内存图来讲解:
在这里插入图片描述
我们在创建对象的时候,在堆内存中开创了一段内存空间,并给了一个内存地址,假如是0x123,当我们给age赋值的时候,实际上是将这个值存在了堆内存的0x123这个地址的内存空间中,而栈内存中的p拿到的只是0x123这个地址值。当执行到 return p 的时候,return需要进行一个备份,而return备份的是“=”右边的0x123这个内存地址。在return进行备份的时候,finally执行了,将age的值变成了28。那我们再去打印这个age的值的时候,实际上打印的是0x123这个内存地址的值,就是28.

还有一种情况:

  • 示例代码二:
public static void main(String[] args) {
        int m = demo();
        System.out.println(m);
    }
    public static int demo(){
        int a = 10;
        try{
            return a;
        }catch (Exception e){
            return 0;
        }finally {
           a = 20;
        }
    }
    static class Person{
        int age;
    }

那这种情况又会输出什么呢?
可能有的小伙伴就会说,这个和上面不是一样吗,finally在return准备的时候执行了,肯定输出20啊!
那你就错了~~实际上输出的值还是10。在这里插入图片描述
为什么?上图!
在这里插入图片描述
我们在定义a = 10的时候,实际上是在栈内存里面开辟了一段内存空间 a = 10,那下边走到return的时候,return进行备份了,那这个备份实际上也是备份“=”右边的值,也就是10,将它备份到一边。这时候,finally还是执行了,但是它执行改变的栈内存里面的值(还是10),将10变为了20;当我们打印age的时候,其实打印的是return已经备份好在旁边的那个“10”。

这就是引用数据类型(前者)和基本数据类型(后者)的区别所在,一个是在堆内存开辟空间,一个是在栈内存开辟空间。

好了,上面说到,无论什么情况,finally代码都会执行,但是以下两种情况除外:

  1. 硬件设备导致程序停止,如:电脑断电、关机、内存资源消耗完了等;
  2. 通过指令控制程序退出JVM,如System.exit();
    这个指令有两个参数,分别是0和1:
    0表示正常退出,程序正常执行结束退出;
    1表示非正常退出,就是说无论程序正在执行与否,都退出。
  • 示例代码:
    public static void main(String[] args) {
        try{
            int a = 10;
            int b = 0;
            System.out.println(a/b);
        }catch (Exception e){
            System.out.println("出现了异常,退出!");
            System.exit(0);//0表示正常退出
        }finally {
            System.out.println("123456");
        }
    }

在这里插入图片描述
上面可以看出,我们的finally代码块并没有执行,这就是在finally执行前,将整个程序终止运行的方法。
好啦,暂时先分享到这里!

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值