Java 异常

Java 异常分类与类结构图

在这里插入图片描述

Java 异常分类

Throwable 是所有异常类 Exception 和错误类 Error 的父类

Error

  • Error 类代表了 JVM 本身的错误。一般有 虚拟机错误(VirtualMachineError)、线程死锁(ThreadDead)

Exception 分为检查异常和非检查异常(RuntimeException)

  • 非检查异常 RuntimeException:在程序运行时可能会抛出该异常,如:空指针异常(NullPointException)、数组下标越界异常(ArrayIndexOutOfBoundsException)、类型转换异常(ClassCastException)、算数异常(ArithmeticException)等
  • 检查异常:在程序编译阶段发生,可以使用 try-catch 语句捕获,如:文件异常(IO Exception)、SQL异常(SQLException)。

异常处理方式

1、遇到问题不进行具体处理,而是继续抛给调用者 (throw,throws)

  • 抛出异常有三种方式:
    1、系统自动抛出异常
    public static void main(String[] args) {
    	int a = 5;
    	int b = 0;
    	System.out.println( a / b);
    }
    
    2、throw
    public static void main(String[] args) {
        String s = "abc";
        if (s.equals("abc")) {
            throw new NumberFormatException();
        } else {
            System.out.println(s);
        }
    }
    
    3、throws
    int div(int a, int b) throws Exception {
        return a / b;
    }
    

2、使用 try-catch 语句捕获

  • try 不能单独出现,后面必须至少跟 catch 或 finally
  • catch 捕获异常并处理后,finally 语句最终会被执行

throw 与 throws 的区别

位置不同:

  1. throws 用在函数上,后面跟的是异常类,可以跟多个;而 throw 用在函数内,后面跟的
    是异常对象。

功能不同:

  1. throws 用来声明异常,让调用者只知道该功能可能出现的问题,可以给出预先的处理方式;throw 抛出具体的问题对象,执行到 throw,功能就已经结束了,跳转到调用者,并将具体的问题对象抛给调用者。也就是说 throw 语句独立存在时,下面不要定义其他语句,因为执行不到

  2. throws 表示出现异常的一种可能性,并不一定会发生这些异常;throw 则是抛出了异常,执行 throw 则一定抛出了某种异常对象。

  3. 两者都是消极处理异常的方式,只是抛出或者可能抛出异常,但是不会由函数去处理异常,真正的处理异常由函数的上层调用处理。

异常的链化

引用自 https://www.cnblogs.com/lulipro/p/7504267.html

在一些大型的,模块化的软件开发中,一旦一个地方发生异常,则如骨牌效应一样,将导致一连串的异常。假设B模块完成自己的逻辑需要调用A模块的方法,如果A模块发生异常,则B也将不能完成而发生异常,但是B在抛出异常时,会将A的异常信息掩盖掉,这将使得异常的根源信息丢失。异常的链化可以将多个模块的异常串联起来,使得异常信息不会丢失。

异常链化:以一个异常对象为参数构造新的异常对象。新的异对象将包含先前异常的信息。

这项技术主要是异常类的一个带Throwable参数的函数来实现的。这个当做参数的异常,我们叫他根源异常(cause)。

查看 Throwable 类源码,可以发现里面有一个 Throwable 字段 cause,就是它保存了构造时传递的根源异常参数。这种设计和链表的结点类设计如出一辙,因此形成链也是自然的了。

public class Throwable implements Serializable {
    private Throwable cause = this;
   
    public Throwable(String message, Throwable cause) {
        fillInStackTrace();
        detailMessage = message;
        this.cause = cause;
    }
     public Throwable(Throwable cause) {
        fillInStackTrace();
        detailMessage = (cause==null ? null : cause.toString());
        this.cause = cause;
    }
    
    ......
}

下面是一个例子,演示了异常的链化:从命令行输入2个int,将他们相加,输出。输入的数不是int,则导致getInputNumbers异常,从而导致add函数异常,则可以在add函数中抛出一个链化的异常。

public class Test {
    public static void main(String[] args) {

        System.out.println("请输入2个加数");
        int result;
        try {
            result = add();
            System.out.println("结果:" + result);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //获取输入的2个整数返回
    private static List<Integer> getInputNumbers() {
        List<Integer> nums = new ArrayList<>();
        try (Scanner scan = new Scanner(System.in)) {
            int num1 = scan.nextInt();
            int num2 = scan.nextInt();
            nums.add(num1);
            nums.add(num2);
        } catch (InputMismatchException immExp) {
            throw immExp;
        }
        return nums;
    }

    //执行加法计算
    private static int add() throws Exception {
        int result;
        try {
            List<Integer> nums = getInputNumbers();
            result = nums.get(0) + nums.get(1);
        } catch (InputMismatchException immExp) {
            throw new Exception("计算失败", immExp);  // 链化:以一个异常对象为参数构造新的异常对象。
        }
        return result;
    }
}

在这里插入图片描述

自定义异常注意事项

父类方法 throws 的是2个异常,子类就不能 throws 3个及以上的异常。父类 throws IOException,子类就必须 throws IOException 或者 IOException 的子类。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值