【Java】异常基本知识点

异常

image-20230526195959624

一、Error

Java虚拟机无法解决的严重问题。如:JVM系统内部错误、资源耗尽等严重情况。比如StackOverflowError和OOM。一般不编写针对性的代码进行处理。

二、Exception

其它因编程错误或偶然的外在因素导致的一般性问题,可以使用针对性的代码进行处理。例如:

  • 空指针访问
  • 试图读取不存在的文件
  • 网络连接中断
  • 数组下标越界

三、异常的结构

image-20230526095124653

四、Java异常处理的方式

1、捕获异常的有关信息(两个常用方法)

与其它对象一样,可以访问一个异常对象的成员变量或调用它的
方法。

  • getMessage() 获取异常信息,返回字符串
  • printStackTrace() 获取异常类名和异常信息,以及异常出现在程序中的位置。返回值void。

2、try-catch-finally(抓抛模型)

伪代码:

try{
...... //可能产生异常的代码
}
//**catch块中的参数e表示捕获到的异常对象**
catch( ExceptionName1 e ){
...... //当产生ExceptionName1型异常时的处置措施
}
catch( ExceptionName2 e ){
...... //当产生ExceptionName2型异常时的处置措施
}
finally{
......
//无论是否发生异常,都无条件执行的语句
} 

image-20230526175357271

a、深入理解finally

捕获到异常的情况

public class Main {
    @Test
    public void test(){
        System.out.println(number());
    }

    static public int number(){
        int i=3;
        int t=0;
        int f = 1;
        try {
            f = i/t;
            return f;
        }
        catch (ArithmeticException e){
            System.out.println("跟踪:");
            e.printStackTrace();

        }finally {
            t = 3;
            System.out.println("\n运行完成");
        }
        return f;
    }
}

想一想这段代码输出的是什么?

我们通过这个例子发现try-catch-finally出现异常后的运行路线

image-20230526183525285

通过这个运行结果我们推断出如果出现异常则在try语句中异常后面的代码将不会被执行。那么就可能在try中出现内存泄露,例如:

在创建一个对象的过程中出现异常,此时对象已经被创建好了。但是由于异常进入了catch语句中导致try中出现异常部分后面的代码不再运行,就可能导致内存无法被回收。此时也体现出了finally的作用,可以将回收内存的语句放入finally中回收掉。

没有捕获到异常的情况

public class Main {
    @Test
    public void test(){
        System.out.println("num = "+number(10));
    }

    static public int number(int num){
        try {
            System.out.println("开始");
            return num;
        }
        catch (NumberFormatException e){
            System.out.println("跟踪:");
            e.printStackTrace();
            return num--;
        }finally {
            System.out.println("\n运行完成");
            ++num;
        }
    }
}

运行结果:

image-20230526185305257

为什么num的值为10?根据debug我们分析出代码的运行过程如下:

image-20230526185916237

image-20230526190118162

既然是这样运行那么为什么返回结果是10而不是11??

此时我们就要知道一个叫做栈帧的东西,里面最常用的局部变量表操作栈

栈帧(Stack Frame)是计算机内存中用于存储函数调用相关信息的一块内存区域,也称为活动记录(Activation Record)、栈针(Stack Pointer)或帧(Frame)。每当一个函数被调用时,都会在栈上创建一个新的栈帧,用于保存函数的参数、局部变量、返回地址和其他与函数执行相关的信息。

栈帧通常由以下几个部分组成:

  1. 参数:用于存储函数调用时传递的参数值。
  2. 返回地址:用于保存函数执行完后返回到调用点的地址。
  3. 动态链接:用于指向调用函数的上一个栈帧,以便函数执行完后返回到正确的调用点。
  4. 局部变量:用于存储函数内部定义的局部变量。
  5. 其他相关信息:如异常处理信息、CPU寄存器保存等。

栈帧的创建和销毁是通过栈指针(Stack Pointer)来完成的。栈指针指向当前栈帧的顶部,在函数调用时将栈指针移动到下一个空闲位置以创建新的栈帧,函数执行完毕后将栈指针恢复到上一个栈帧的位置以销毁当前栈帧。

栈帧的使用使得函数调用可以按照嵌套的方式进行,每个函数都有自己独立的栈帧,可以在不同的函数之间传递参数和返回结果。同时,栈帧的创建和销毁由系统自动管理,无需手动操作,大大简化了函数调用的过程。

局部变量表(Local Variable Table)是JVM中一块用于存储方法中局部变量的数据结构。局部变量表位于每个线程的栈帧中,用于存储方法中声明的局部变量、方法参数以及中间计算结果等。

操作栈(Operand Stack)在JVM中,操作栈是一块用于存储方法执行过程中操作数的数据结构,也称为运行时数据栈或操作数栈。

image-20230526191621642

根据这个内存图,我们知道在number方法中return操作后的数据被放在操作栈中,而num操作后的数据被放在局部变量表中。所以即使++num以后使num值为11,但此时是将操作栈中的数据返回,所以此时输出还是10。

3、throws

抛出异常,一直将异常向上抛,直到解决为止。

五、throws存在时方法重写的要求(针对编译异常)

子类重写的方法抛出的异常类型可以和父类抛出的异常相同,或是抛出父类异常的子类。

六、开发时如何选择两种异常

1、try-catch-finally

  • 资源需要被执行时(涉及流,网络等)
  • 方法重写(父类中没有解决子类异常的try-catch-finally语句)

2、throws(声明、处理)

  • 方法嵌套时(将所以异常抛到最后处理)

image-20230526221650037

七、自定义异常(手动抛出)throw

自定义异常,然后对异常分析处理。

package Day1;
/*
 *项目名: OneDayLearn1
 *文件名: MAIN
 *创建者: SWY
 *创建时间:2023/5/27 下午2:50
 *描述: TODO
 */

import java.util.Enumeration;

public class MAIN {
    public int number = 0;
    public static void main(String[] args){
        MAIN m = new MAIN();
        int i = -1124524;

        try {
            m.number(-10);
        } catch (StudentNumberException e) {
           e.printStackTrace();
        }

        System.out.println("number = "+m.number);
    }
	
    //声明方法异常
    public void number(int i) throws StudentNumberException {
        if(i>0){
            this.number = i;
        }    
        else{
            //抛出异常
            throw new StudentNumberException("输入非法值");
        }
    }
}

//自定义异常
class StudentNumberException extends Exception{
    public StudentNumberException(String i){
        super(i);
        System.out.println("异常类");
    }
}

image-20230527160624221

为什么程序在最后打印异常信息??

异常的堆栈信息是由Java虚拟机(JVM)生成和管理的,通常情况下,当异常发生时,JVM会尝试查找能够处理该异常的catch块,并跳转到相应的代码块执行异常处理逻辑。执行完异常处理逻辑后,程序会继续执行正常的流程。

在程序结束后,JVM会进行一些清理工作,包括打印异常信息。这样做的目的是为了提供完整的异常信息,让开发者能够更好地理解和排查问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

摸鱼小小虫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值