异常学习笔记

异常


基本概念:程序在运行过程中出现的特殊情况

异常处理的必要性:任何程序都可能存在大量的未知问题,错误;如果不对这些问题进行正确处理,则可能导致程序的中断,造成不必要的损失。

异常即为Throwable,他是一切异常的父类,位于java.lang包下

Throwable又分为Error和Exception两个子类

Error


基本概念

指JVM,硬件,或执行逻辑错误,不能手动处理

程序员一定要(避免)Error产生

无穷递归即是一个很经典的Error错误

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

    public static void test(){
      test();
    }

Exception


基本概念

指程序在运行和配置中产生的问题,可以处理

  • Exception分为CheckedException和RuntimeException两大类
  • CheckedException为受查异常,必须处理或者声明
  • RuntimeException为运行时异常,可以不进行处理,也可以不声明

异常的产生

一般的Exception异常都是通过throw new 异常类()来进行异常的抛出,从而产生异常

异常的声明

如果某个方法产生了异常,那么这个方法可以throws该异常名进行声明(RuntimeException可不进行声明,CheckedException如果没处理异常则必须声明)

当遇到某个方法体中遇到无法处理的异常时,也可以将其声明出去,由调用该方法的人进行处理

异常声明尽量要与throw的异常相同,这样处理时更方便快捷

异常的传递

在调用方法时,如果某个方法中产生了异常,则会立刻中断该方法,而且会顺着递归方向进行传递,如果调用这个方法的方法没有处理这个异常,则会继续中断该方法且继续传递,直到传入main方法中也没进行处理,则会中断main方法同时将异常传递进JVM虚拟机中,由JVM处理该异常并打印堆栈跟踪信息

异常的处理

异常一般情况下通过try{}catch(){}finally{}结构进行捕获处理

其中try包含的是最可能产生异常的代码块,如果在try中产生异常,则会立刻中断try后的所有代码,转而由catch捕获对应的异常并进行处理,同一结构中catch可以进行多次捕获来处理由小到大范围的异常

try {
            int[] acc=new int[10];
        } catch(NullPointerException n){

        }catch (RuntimeException r) {

        } catch (Exception e) {

        } finally {
            
        }

finally代码块中的代码一定会被执行到,所以常用来释放空间和垃圾回收

如果try,catch和finally代码块中都含return语句,则无论什么情况都会返回finally中的return值,具体实现机制可看本文最后

处理方案一般情况下可分为三种:catch(Exception e){ 处理方案 }

1.sout(“你想说出的话”)  //通过自己的语句警告

2.e.printStackTarce()  //打印堆栈信息

3.e.getMessage()  //打印异常中的Message属性存储的信息

值得一提是,如果你想使用第三种方法来处理,则必须抛出异常时,调用的是有参的构造方法,即Exception对象中已经含有Message值了,这样你就可以打印出Message值了

以下为Throwable类中构造方法:

 private String detailMessage;

 public Throwable(String message) {
        fillInStackTrace();
        detailMessage = message;
    }

 public String getMessage() {
        return detailMessage;
    }

以下为其子类的构造方法:

 public Exception(String message) {
        super(message);
    }

带有异常声明的方法覆盖

当你自己定义了一个类或接口且该类中含有声明异常的方法时,如果你想继承这个类或者实现这个接口,注意:

如果你重写后的方法想继续抛出异常,则异常声明范围必须小于等于父类本身方法声明的异常

class Father{
    public void test() throws Exception {
        throw new Exception();
    }
}

class Son extends Father{
    public void test() throws Exception{
        throw new Exception();
        System.out.println("override");
    }
}

这是为了防止多态调用所产生的问题

自定义异常类

如果某些情况下,你发现抛出即声明异常不能产生望文生义的效果,你可以自定义异常类,如下图:

class NumberNotEqualTenException extends Exception{

}

则当你某个方法需要用的该异常时则可throw相应异常

public void setNumber(int n) throws NumberNotEqualTenException {
        Scanner sc = new Scanner(System.in);
        int num = n;
        if (num == 10){
            throw new NumberNotEqualTenException();
        }
    }

你就可以在调用时看到效果了

 异常中经典的Return问题

当你碰见如下代码时,你会认为返回值是多少?

public int test(){
        int a = 10;
        try {
            a = 20;
            throw new Exception();
        } catch (Exception e) {
            a = 30;
            return a;
        } finally {
            a = 40;
        }
    }

答案是30,具体处理机制如下图

上图为JVM虚拟机处理字节码文件,我们可以看见,当执行到iload_0时,即准备执行return语句,但由于有finally代码块的存在,必须执行其中的内容,所以又临时将存储在栈顶的30放在了局部变量3中,直到finally代码块执行完毕后,iload_3将30加载到栈顶后ireturn返回

上图右边部分又被称为栈帧结构,存在于JVM栈中,每一个栈帧结构对应一个方法

从此图也可以看出方法的执行顺序,每当一个栈帧结构进栈时执行,而当另一个栈帧结构进栈则先执行,即优先执行栈顶元素

本文章仅供个人参考学习,欢迎各位大佬交流与改正

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值