Java的异常机制详解

本文深入解析Java中的异常处理机制,包括异常的分类、运行时异常与编译时异常的区别,以及如何使用try-catch、throws等关键字进行异常的捕获与抛出。同时,文章还介绍了finally块的用途及自定义异常的创建方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.Exception异常的分类

在这里插入图片描述

  1. 编译时异常:继承自Exception的异常或者其子类,没有继承RuntimeException。编译阶段就会报错,必须程序员处理,否则代码编译就不能通过。
  2. 运行时异常:继承自RuntimeException的异常或者其子类。该异常可以处理也可以不处理,编译阶段是不会报错的,但在运行阶段可能会出错,建议处理。

2.运行时异常

2.1 ArrayIndexOutOfBoundsException

        int[] a = {1,2};
        System.out.println(a[2]);//ArrayIndexOutOfBoundsException

2.2 NullPointerException

        String s = null;
        System.out.println(s);//null
        System.out.println(s.length());//NullPointerException

2.3 ClassCastException

        Object s = "abc";
        Integer i = (Integer)s;//ClassCastException

2.4 ArithmeticException

		System.out.println(2/0);//ArithmeticException

2.5 NoSuchElementException

        ArrayList<String> arr = new ArrayList<>();
        arr.add("1");

        Iterator<String> iterator = arr.iterator();
        iterator.next();
        System.out.println(iterator.next())//NoSuchElementException

2.6 NumberFormatException

        String s = "123abc";
        Integer i = Integer.valueOf(s);//NumberFormatException

3.编译时异常

public class ExceptionDemo {
    public static void main(String[] args) {//没有在main函数处throws ParseException
        String time = "2020-5-25 14:27";
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy:MM-dd HH:mm");
        Date date = sdf.parse(time);//此处会编译异常
        System.out.println(date);
    }
}

4.异常的处理

4.1 异常的默认处理机制

  1. 默认会在出现异常的代码那里自动的创建一个异常对象,例如:ArithmeticException
  2. 异常会从方法中出现的点这里抛出给调用者,调用者最终抛出给JVM虛拟机
  3. 虚拟机接收到异常对象后,先在控制台直接输出异常栈信息数据。
  4. 直接从当前执行的异常点干掉当前程序。
  5. 后续代码没有机会执行了,因为程序已经死亡。

小结:异常一旦出现,会自动创建异常对象,最终抛出给虚拟机,虚拟机只要收到异常,就直接输出异常信息,干掉程序!!

默认的异常处理机制并不好,一旦真的出现异常,程序立即死亡!

4.2 编译时异常的处理方式

4.2.1: Throws(抛出异常)

public class ExceptionDemo {
    public static void main(String[] args) throws Exception {//抛出异常
        String time = "2020-5-25 14:27";
        parseTime(time);
    }
    public static void parseTime(String s) throws Exception {//抛出异常
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
        Date date = sdf.parse(s);
        System.out.println(date);
    }
}

在岀现编译时异常的地方层层把异常抛出去给调用者,调用者最终抛出给JVM虚拟机。

JVM虚拟机输出异常信息,直接干掉程序,这种方式与默认方式是一样的。

虽然可以解决代码编译时的错误,但是一旦运行时真的出现异常,程序还是会立即死亡

这种方式并不好!

4.2.2: try-catch(捕获处理)

监视捕获处理异常企业级写法:
try {
//可能出现异常的代码!
} catch (Exception e){

​ e, printStackTrace();//直接打印异常栈信息

}

public class ExceptionDemo {
    public static void main(String[] args) {
        String time = "2020-5-25 14:27";
        parseTime(time);
    }
    public static void parseTime(String s){
        try{
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
            Date date = sdf.parse(s);
            System.out.println(date);
        } catch (ParseException e) {
            e.printStackTrace();
        }
    }
}

Exception可以捕获处理一切异常类型!

小结

第二种方式,可以处理异常,并且出现异常后,代码也不会死亡。

这种方案还是可以的。

但是从理论上来说,这种方式不是最好的,上层调用者不能直接知道底层的执行情况

4.2.3: try-catch,throws

方式三:在出现异常的地方把异常一层一层地抛出给最外层调用者,最外层调用者集中捕获处理!!(规范做法)

编译时异常的处理方式三:底层出现的异常抛出给最外层调用者集中捕获处理。

public class ExceptionDemo {
    public static void main(String[] args) {
        try{
            String time = "2020-5-25 14:27";
            parseTime(time);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
    public static void parseTime(String s) throws Exception {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
        Date date = sdf.parse(s);
        System.out.println(date);
    }
}

总结:这种方案最外层调用者可以知道底层执行的情况,同时程序在出现异常后也不会立即死亡,这是理论上最好的方案。

虽然异常有三种处理方式,但是实际中只要能解决你的问题,每种方式都又可能用到!!

4.3 运行时异常的处理方式

运行时异常编译阶段不报错,可以处理也可以不处理,建议处理!

运行时异常可以自动抛出,不需要我们手工抛出。

运行时异常的处理规范:直接在最外层(try-catch)捕获处理即可,底层会自动抛出!

public class ExceptionDemo {
    public static void main(String[] args) {
        try{
            devide(3,0);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public static void devide(int a,int b) {
        System.out.println(a/b);
    }
}

5.finally

用在捕获处理的异常格式中的,放在最后面。

try {
//可能出现异常的代码!

}catch(Exception e){

​ e.printstackTrace();

} finally {

​ //无论代码是出现异常还是正常执行,最终一定要执行这里的代码!!

}

try:1次

catch:0-N次(如果有finally那么 catch可以没有!!)

finally:0-1次

finally的作用:可以在代码执行完毕以后进行资源的释放操作

资源:实现Closeable接口的,自带close()关闭方法。

public class ExceptionDemo {
    public static void main(String[] args) {
        func();
    }
    public static void func() {

        try{
            System.out.println(10/0);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            System.out.println("====finally被执行====");
        }
    }
}

/*

java.lang.ArithmeticException: / by zero
        at zbr.ExceptionDemo.func(ExceptionDemo.java:10)
        at zbr.ExceptionDemo.main(ExceptionDemo.java:5)
        ====finally被执行====
        
*/

6.异常的注意事项

  1. 运行时异常可以被自动抛出,被抛出时可以不处理;编译时异常需手动抛出,必须处理。按照规范两种异常都该被处理。
  2. 重写方法时,子类声明抛出的异常类型必须是其父类抛出的异常类型或是其子类。
  3. 在try-catch后可以加finally代码块,其中的内容一定会被执行,通常用于资源回收操作。

7.自定义异常

7.1 自定义编译时异常

(编译时异常是编译阶段就报错,提醒更加强烈,一定需要处理!!)

  1. 定义一个异常类继承 Exception 。

  2. 重写构造器。

  3. 在出现异常的地方用 throw new自定义对象抛出!

    class AgeException extends Exception {
        public AgeException() {
            super();
        }
    
        public AgeException(String message) {
            super(message);
        }
    
        public AgeException(String message, Throwable cause) {
            super(message, cause);
        }
    
        public AgeException(Throwable cause) {
            super(cause);
        }
    
        protected AgeException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
            super(message, cause, enableSuppression, writableStackTrace);
        }
    }
    
    public class ExceptionDemo {
        public static void main(String[] args) {
            try {//因为是编译时异常,所以需要对抛出的异常做处理
                isAge(-1);
            } catch (AgeException e) {
                e.printStackTrace();
            }
        }
        public static void isAge(int age) throws AgeException {//需要抛出异常
            if (age<0||age>200) {
                throw new AgeException("非法年龄");//在输入的年龄不符合时会抛出一个自定义的异常对象
            }else {
                System.out.println("年龄是:"+age);
            }
        }
    }
    

7.2 自定义运行时异常

(提醒不强烈,编译阶段不报错!!运行时才可能出现)

  1. 定义一个异常类继承 RuntimeException
  2. 重写构造器。
  3. 在出现异常的地方用 throw new自定义对象抛出!
class MyArithmeticException extends ArithmeticException {
    public MyArithmeticException() {
        super();
    }

    public MyArithmeticException(String s) {
        super(s);
    }
}

public class ExceptionDemo {
    public static void main(String[] args) {
        devide(1,0);
    }
    public static void devide(int a, int b) {
        if (b==0) {
            throw new MyArithmeticException("除数不能为0");
        }else {
            System.out.println(a/b);
        }
    }
}
//Exception in thread "main" zbr.MyArithmeticException: 除数不能为0

8.总结

  1. 异常可以处理代码问题,防止程序出现异常后死亡。
  2. 提高程序的健壮性和安全性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值