Java 中的异常机制

本文详细介绍了Java中的异常处理机制,包括异常的类型如编译时异常和运行时异常,以及如何自定义异常。文章还讨论了如何通过try-catch-finally语句进行异常捕获和处理,以及使用throws关键字声明和抛出异常。此外,提到了断言表达式在程序调试中的作用。
摘要由CSDN通过智能技术生成

Java中的异常机制

异常的类型

异常类型的本质依然是类的对象

异常也是一个类,都继承自Exception类;

异常类型支持提前报错

运行时异常

在编译中无法感知代码是否会出现问题,只有在运行时才知道出错。异常也是由类定义的,所有运行时异常都继承自RuntimeException

public static void main(String[] args) {
    Object object = null;
    object.toString();   //这种情况就会出现运行时异常
}

报错

在这里插入图片描述

编译时异常

指出可能出现的异常,在编译阶段需要进行处理(捕获异常)必须要考虑到出现异常的情况,如果不进行处理,将无法通过编译。

默认继承自Exception类的异常时都是编译时异常

错误

异常不一定会导致致命的问题,但是错误会

比如OutOfMemoryError就是内存溢出错误;无限递归

自定义异常

异常分为两类,编译时异常和运行时异常

编译时异常

public class TestException extends Exception{
    public TestException(String message) {
        super(message); //选择使用父类的带参构造,这个参数就是异常的原因
    }
}

编译时异常只需要继承Exception就行了,因为子类巨多

在这里插入图片描述

运行时异常

运行时异常只需要继承RuntimeException就行了

public class TestException extends RuntimeException{
    public TestException(String message){
        super(message);
    }
}

在这里插入图片描述

由此可见 Exception继承自Throwable,RuntimeException继承自Exception

运行时异常同同样也有很多,只不过运行时异常和编译型异常在使用时有一些不同,我们会在后面的学习中慢慢认识。

当然还有一种类型是Error,它是所有错误的父类,同样是继承自Throwable的。

抛出异常

当别人调用我们的方法,传入错误的参数导致程序无法运行,这时就可以手动抛出一个异常来终止程序继续运行下去,同时告知上一级方法执行出现了问题

    public static int test(int a,int b) {
        if(b==0) {
            throw new RuntimeException("被除数不能为0");
        }
        return a/b;
    }

异常的抛出同样需要创建一个异常对象出来,抛出异常实际上是将这个异常对象抛出。异常对象携带了抛出异常时的一些信息,比如因为什么原因导致的异常,在RuntimeError的构造方法中写入原因

当出现异常时

在这里插入图片描述

程序会终止,并且打印栈追踪信息,这里的两个at就是在告知程序运行到哪里出错,位于最上面的就是发生异常的最核心位置。

并且这里会打印出当前抛出的异常类型和我们刚刚自定义异常信息

非运行时异常

如果在方法中抛出非运行时异常,那么必须告知函数的调用方法会抛出某个异常,函数调用方必须要对抛出的这个异常进行相应的处理

private static void test() throws Exception {    //使用throws关键字告知调用方此方法会抛出哪些异常,请调用方处理好
    throw new Exception("我是编译时异常!");
}

如果不同分支出现不同的异常,那么所有方法中可能会抛出的异常都需要注明

private static void test(int a) throws FileNotFoundException, ClassNotFoundException {  //多个异常使用逗号隔开
    if(a == 1)
        throw new FileNotFoundException();
    else 
        throw new ClassNotFoundException();
}

并不是只有非运行时异常可以明确指出,运行时异常也可以,但是不强制要求

private static void test(int a) throws RuntimeException {
	throw new RuntimeException();
}

父类异常情况下子类

在重写方法时,如果父类中的方法表明了会抛出某个异常,只要重写内容中不会抛出对应的异常我们就可以省略

@Override
protected Object clone() {
    return new Object();
}

异常的处理

当程序没有按照我们预想的结果运行而出现异常时,为了让程序继续运行下去,就需要对异常进行捕获

try-catch

如果某个方法明确指出抛出哪些异常,除非抛出的异常是一个运行时异常,否则我们必须要使用try-catch语句进行异常的捕获,不然无法通过编译

我们可以将代码编写到try语句中,只要是在这个范围内发生的异常,都可以被捕获,使用catch关键字对指定的异常进行捕获

public static void main(String[] args) {
    try{
        Object object = null;
        object.toString();
    }catch(NullPointerException e) { //异常本身也是一个对象,所以是利用一个局部变量接收异常
        
    }
    System.out.println("程序正常运行!");
}

之后可以看到当我们捕获异常,程序可以继续正常运行,并不会像之前一样直接结束。

catch的捕获类型只能是Throwable的子类,也就是说要么是抛出的异常,要么就是错误,不能是其他的子类

我们也可以在catch语句块中对捕获的异常进行处理

public static void main(String[] args) {
    try {
        Object object = null;
        object.toString();
    } catch (NullPointerException e) {
        e.printStackTrace();
        System.out.println("异常消息"+e.getMessage());
    }
    System.out.println("程序继续正常运行");
}

在这里插入图片描述

如果某个方法明确指出会抛出哪些异常,除非抛出的异常是一个运行时异常,否则我们必须要使用try-catch语句块进行异常的捕获,不然就无法通过编译:

public static void main(String[] args) {
    test(10); //会出现异常报错
}

private static void test(int a) throws IOException {
    throw new IOException();
}

如果我们不想在当前方法处理。那就继续throw

注意,如果已经是主方法了,那么就相当于到顶层了,此时发生异常再往上抛出的话,就会直接交给JVM进行处理,默认会让整个程序终止并打印栈追踪信息

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

private static void test(int a) throws IOException {
    throw new IOException();
}

如果需要捕获的异常是个异常的父类,那么当发生这个异常,同样可以捕获到

public static void main(String[] args) throws IOException {
    try {
        int[] arr = new int[1];
        arr[1] = 100;    //这里发生的是数组越界异常,它是运行时异常的子类
    } catch (RuntimeException e){  //使用运行时异常同样可以捕获到
        System.out.println("捕获到异常");
    }
}

多重异常捕获

但是要注意顺序,父类在前,会将子类的也捕获,之后的错误就永远都不会捕获了

try {
  //....
} catch (NullPointerException e) {
            
} catch (IndexOutOfBoundsException e){

} catch (RuntimeException e){
            
}

简写

try {
     //....
} catch (NullPointerException | IndexOutOfBoundsException e) {  //用|隔开每种类型即可
		
}

当我们希望,程序运行时,无论是否出现异常,都会在最后执行任务,可以交给finally语句块来处理:

try {
    //....
}catch (Exception e){
            
}finally {
  	System.out.println("lbwnb");   //无论是否出现异常,都会在最后执行
}

**try语句至少要配合catch或者finally中的一个

断言表达式

我们可以使用断言表达式来对某些东西进行判断,如果判断失败会抛出错误,只不过默认情况下没有开启断言,我们需要在虚拟机参数中手动开启

需要使用到assert关键字,如果判断结果为false,则会出现AssertionError错误

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值