JavaSE进阶第十三天——异常

23 篇文章 0 订阅
15 篇文章 0 订阅

异常

异常的概念

概念:在java代码运行过程中,遇到不正常的事件,从而导致代码运行中断的就是异常。

异常的分类

看图理解:
在这里插入图片描述

Throwable类下有两个类:Erro类和Exception类
Erro类:java程序执行过程中发生错误且无法解决,则退出执行。例如:java.lang.StackOverFlowErro
Exception类又分为两个类:

  1. Exception直接子类:称为编译时异常/受控异常/检查异常。java中规定,此类异常在java编译阶段必须处理。否则编译无法通过。
  2. RunTimeException:称为运行时异常/非受控异常/未检查异常。java中规定,运行时异常可以不在编译阶段处理也能通过编译。

异常的处理

处理异常的关键字:

  1. throw:抛出异常
    在这里插入图片描述

  2. throws:上抛异常
    在这里插入图片描述

  3. try:监控异常代码,配合catch和finally使用
    在这里插入图片描述

  4. catch:捕捉异常,需要配合try使用
    在这里插入图片描述

  5. finally:不论结果如何最终finally中的代码总会输出
    在这里插入图片描述
    异常的处理方法:

  6. try…catch:捕捉异常

try{
	这里写要监控的代码,也就是可能出现异常的代码
}catch(这里写可能出现的异常名称 变量名){
	e.printStackTrace();//这个方法表示输出异常详细信息
	e.getMessage();//这个方法表示获取异常简单信息,注意,这是获取,不会输出
}

例如:按照控制台提示输入1~3之间任一个数字,程序将输出相应的课程名称根据键盘输入进行判断。如果输入正确,输出对应课程名称。如果输入错误,给出错误提示

/**
 * 课程查询
 */
public class CurriculumQuery {

    public static void main(String[] args) {
        //创建键盘扫描器
        Scanner s = new Scanner(System.in);

        //课程代号
        int cno;

        System.out.print("请输入课程代号(1~3之间的数字):");


        //判断输入是否正确,正确则输出课程,错误则输出提示信息
        try {
            cno = s.nextInt();
            judgeCno(cno);
        }catch (InputFigureException e) {

            //给出详细提示
            //e.printStackTrace();

            //给出简单提示
            System.out.println(e.getMessage());

        }finally {
            System.out.println("欢迎提出建议");
        }
    }

    /**
     * 判断输入是否正确,错误则返回提示。正确则输出对应课程
     * @param cno : 课程代号
     * @throws InputFigureException : 输入错误异常提示
     */
    public static void judgeCno(int cno) throws InputFigureException{
        if (cno > 3 || cno < 1 ){
            throw new InputFigureException("输入的数字不在范围内");
        }else{
            if (cno == 1){
                System.out.println("C#编程");
            }else if (cno == 2){
                System.out.println("Java编程");
            }else if (cno == 3){
                System.out.println("Python编程");
            }
        }
    }
}
/**
 * 输入数字异常
 */
class InputFigureException extends Exception{
    //无参构造
    public InputFigureException() {
    }
    //有参构造
    public InputFigureException(String message) {
        super(message);
    }
}

  1. throws上抛异常
    即自身不处理异常,而是将异常抛出给调用类或jvm。
    例如上面代码中的方法:
    在这里插入图片描述划线处就是上抛异常,将异常抛给调用这个方法的调用者。让调用者去处理,若是调用者无法处理可以继续上抛直到抛给jvm。(我是这样理解的,应该是最多抛到jvm)

自定义异常

自定义异常步骤:

  1. 自定义异常类需要继承一个异常类作为父类
  2. 自定义异常类中的构造方法使用父类中的构造方法
    在这里插入图片描述

补充知识

  1. try…catch…finally中catch和finally都必须和try在一起才能使用,否则报错。
单独catch ——> 报错
catch(){}

单独finally ——> 报错
finally{}

catchfinally ——> 报错
catch(){}finally{}
  1. 关于finally代码块的执行顺序问题:finally代码块中的代码无论如何最后都会被执行,那么有没有例外呢?
    当然有啊!!!
    先看这个代码:

public class Test {
    public static void main(String[] args) {
        int a = 10;
        int b =0;
        int c = 0;
        try{
            c = a/b;
        }catch (Exception e){
            e.printStackTrace();
        }finally{
            System.out.println("报错了");
        }       
    }
}

看看输出结果是什么:这个时候finally代码块中的代码是执行了的。
在这里插入图片描述再看看这个代码:

public class Test {
    public static void main(String[] args) {
        int a = 10;
        int b =0;
        int c = 0;
        try{
            c = a/b;
        }catch (Exception e){
            e.printStackTrace();
            System.exit(0);
        }finally{
            System.out.println("报错了");
        }

    }
}

输出结果
在这里插入图片描述可以看到,此时finally代码块中的代码就没有执行了。
System.exit(0):表示的是终止当前运行的java虚拟机。查文档可以查到。
在这里插入图片描述

我们再来看另一种情况:
看代码:问输出的i是多少?
答案:11

public class T {
    public static int show() {
        int i = 0;
        try{
            i = 10;
        }finally {
            i++;
        }
        return i;
    }

    public static void main(String[] args) {
        System.out.println(show());
    }
}

再看代码:
此时输出的是多少?
答案:10

public class T {
    public static int show() {
        int i = 0;
        try{
            i = 10;
            return i;
        }finally {
            i++;
        }
    }
    public static void main(String[] args) {
        System.out.println(show());
    }
}

为什么呢?
我知道肯定你们会说因为代码自上而下执行啊。当执行到return i;之后,就返回 i 结束方法了。finally不会执行。实时真是如此吗?
看看这个代码:

public class T {
    public static int show() {
        int i = 0;
        try{
            i = 10;
            return i;
        }finally {
            i++;
            System.out.println("finally输出:"+i);
        }
    }
    public static void main(String[] args) {
        System.out.println(show());
    }
}

输出结果:
在这里插入图片描述
显而易见,finally代码块最终还是会执行的。那到底为什么返回的是10 呢?我看了很多帖子,我不能说他们讲的不好,但是我敢说的是,我讲的更清楚。其实很简单,看图就完了:
看蓝色行,蓝色行就是当前执行行。我们通过打断点debug测试,看看代码的执行顺序。
首先,代码main方法执行,调用show()方法,这没问题吧。
在这里插入图片描述进入show()方法
在这里插入图片描述按照自上而下的顺序一次执行
在这里插入图片描述注意,这里执行了return
在这里插入图片描述继续执行finally代码块
在这里插入图片描述输出11
在这里插入图片描述划重点,发现没有,执行完finally代码块后回回到第7行 return i 这里。然后结束show()方法
在这里插入图片描述show()方法结束,返回值赋值给o。
在这里插入图片描述这时候发现,其实o变量存储的值是10。

在这里插入图片描述
看完流程。我们就可以得到一个结论了。
结论:在finally前面存在return的时候,return会先将值返回,然后程序继续往下执行,当finally代码块中的代码执行完毕后将会再次返回到return行执行return结束方法的功能,但此时的return不会再返回值。return再整个过程中被分为了两部分,先传值,然后等待finally代码块的执行,再结束方法。

关于finally和return的执行还有一点:finally代码块外面有return并且位置处于finally代码块之上,同时finally代码块中还有return。此时我们可以忽略finally代码块之上的return。因为最终执行并返回的是finally代码块中的return。文字很抽象,但是咱还是老办法。打断点debug。

public class Test {

        public static int show() {
            int i = 0;
            try{
                i = 10;
                return i;
            }finally {
                i++;
                System.out.println("finally输出:"+i);
                return i;
            }
        }
        public static void main(String[] args) {
            int o = show();
            System.out.println(o);
        }
}

图是在太多,我就直接标号给你们了
在这里插入图片描述
看顺序,你会发现第7行,也就是第4个执行的代码 return i;其实确确实实执行了,按照上面我说法,先执行的是返回值,然后代码继续向下执行。当执行到finally代码块中的 return i ;时,也就是12行时,按照上面的说法,执行完finally代码块应该掉头回到第7行执行return语句的功能结束代码。但实际上却并不是如此。当finally代码块中存在return语句的时候,此时finally代码块中的return语句后面并不会像第7行的return语句一样将返回值和结束方法功能分开执行。它就是一个正常的return语句。也就是说,finally代码块中的return不仅返回了值还结束了方法。既然结束了方法,那么自然不会再回到第7行去执行return语句。同时,我们根据debug可以知道上面的return语句时执行过的,也就是返回过值,而下面的return又返回了一次,根据执行结果我们能够看出,下面的return返回的值覆盖了上面return的值。所以照我看来,当finally代码块中存在return语句的时候。finally代码块外面的return可以视作空气,忽视掉它。

今天的知识有点绕,大家好好消化。我也要好好消化一下。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值