Java-异常相关知识点

Throwable

假设在Java程序运行期间出现了一个错误,这个错误产生的原因可能是对象不存在、下标错误、网络原因等,有些是外部因素,有些是代码因素。当出现错误时,我们希望能够有一些相应的处理,要么给与提示,要么对错误进行处理,在Java中,是通过抛出和捕捉异常对象进行处理的。
Throwable是Java中所有异常对象的父类,它定义了获取错误信息、栈堆信息、生成异常对象等一系列公共方法,并实现了Serializable接口,可以被序列化。在方法中,当出现异常的时候,可以通过throw将相应的子类异常抛出。

常见的错误类型

  • 用户输入错误
  • 设备错误
  • 物理限制
  • 代码错误

Exception继承体系

在Java 程序设计语言中,异常对象都是派生于Throwable 类的一个实例,所有异常都是由Throwable继承而来,并且分为了Error和Exception。
根据Java中常见的Exception和Error做了一个继承体系图如下。在异常体系中包含受检结构和非受检结构。受检结构即为受检异常,非受检结构包含非受检异常和Error及其子类,非受检异常都是RuntimeException及其子类。
在这里插入图片描述

受检异常

受检异常的作用主要是告诉调用者可能出现什么异常,并要求调用者进行处理或者抛出。如果API的提供者希望调用者来对异常进行处理,那么就可以使用受检异常,通过抛出异常,强制让调用者try-catch,在catch中进行处理或者继续抛出。方法中每个抛出的异常,都是对调用者的一种潜在异常提示,提醒调用者可能发生的问题。如IOException,ClassNotFoundException等。

  • 注意事项
  • 对于可恢复的场景,要抛出受检异常,通知调用者进行处理
  • 要在受检异常上提供方法,以便协助恢复
  • 抛出受检异常的方法不能直接在Stream中使用
  • 对外部提供API的时候,尽量不要使用受检异常,因为调用方需要通过try-catch捕捉处理或者抛出,try-catch模块同时也阻止了JVM本来可能要执行的某些特定优化。
  • 如果打算选择其他方法代替受检异常。可以通过选择提供状态测试方法(如Iterator的hasNext方法)或者optional返回值或者可识别的返回值(null)来解决。如果有并发情况,不要使用状态测试方法,在测试方法执行前后期间对象的状态可能在别的线程被发生了变化。
  • 消除受检异常最容易的方法是,返回所要的结果类型的一个optional。这种方法的缺点是,方法无法返回任何额外的信息,来详细说明它无法执行你想要的计算。相反,异常则具有描述性的类型,并且能够导出方法,以提供额外的信息。

未受检结构

非受检结构包括RuntimeExceptionError
如果程序抛出未受检的异常或者错误,往往就属于不可恢复的情形,继续执行下去有害无益。如果程序没有捕捉到这样的可抛出结构,那么将会导致当前线程中断,并且提示适当的错误信息,比如最常见的NullPointException

RuntimeException

如果出现了RuntimeException,那么一定是程序的问题。比如NullPointerException,这个异常不需要对外抛出,因为我们可以通过代码避免这种异常,因此不需要对外抛出。

  • 对于程序错误,不能继续执行,要抛出运行时异常
  • 不确定是否可恢复,则抛出未受检异常
  • 一般情况下尽量使用JDK中已有的运行时异常,特殊情况下通过继承RuntimeException自定义新的异常
Error

Error 类层次结构描述了Java 运行时系统的内部错误和资源耗尽错误。应用程序不应该抛出这种类型的对象。如果出现了这样的内部错误,除了通告给用户,并尽力使程序安全地终止之外,再也无能为力了,如OutOfMemoryError错误,当抛出这个Error时,基本程序已经无法运行

  • Error是不可控的
  • 错误往往被JVM保留下来使用,以表明资源不足、约束失败,或者其他使程序无法继续执行的条件
  • 最好不要再实现任何新的Error子类

捕获异常

如果某个异常发生的时候没有在任何地方进行捕获,那程序就会终止执行,并在控制台上打印出异常信息, 其中包括异常的类型和堆栈的内容。
要想捕获一个异常, 必须设置try/catch 语句块。如果在try模块中发生了一个异常,那么程序将跳过try模块中剩余代码,执行catch模块中的代码,如果没有发生异常,那么执行完try中代码后,跳过catch代码。

// 捕获异常
try {
	System.out.println(1/0);
} catch (Exception e) {
	e.printStackTrace();
}
// 捕获多个异常
try {
	System.out.println(1/0);
} catch (NullPointerException | ArithmeticException e) {
	e.printStackTrace();
}
转换异常

当捕获到一个异常,想把它转变成其他异常的时候,除了调用其他异常的构造方法,还可以通过使用Throwable中继承的方法initCause,它会产生新的异常并且记录导致这个异常的原因,通过getCause可以获取原因。

try {
	System.out.println(1/0);
} catch (Exception e) {
	RuntimeException e1 = new RuntimeException();
	e1.initCause(e);
	e1.printStackTrace();
}
finally

finally模块中的代码必定会执行。如果try模块中抛出了异常,并且异常被捕捉,执行顺序为try异常前代码-catch-finally; 如果try模块中未发生异常或者发生异常未被捕捉,那么执行顺序为try-finally。

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

finally中的return 会覆盖try中的return

try {
	return 1;
} catch (Exception e) {
	e.printStackTrace();
} finally {
	return 2; // 覆盖
}

因为finally中的语句必定会执行,因此finally中一般也会被用来释放资源,如InputStream和OutStream。

InputStream is = null;
try {
	is = new FileInputStream(new File(""));
	System.out.println(1/0);
} catch (FileNotFoundException e) {
	e.printStackTrace();
} finally {
	try {
		is.close();
	} catch (IOException e) {
	    // 释放资源如果抛出异常可能会覆盖上面的异常
	}
}

如果实现了AutoCloseable接口,那么可以使用带资源的try模块方式,当出现异常或者正常执行结束,程序自动释放资源。

try (InputStream is = new FileInputStream(new File(""))){
	System.out.println(1/0);
} catch (IOException e1) {
	e1.printStackTrace();
} finally {
}

API

  • initCause 生成新的异常对象
  • getCause 获取异常原因
  • getMessage 异常信息
  • getStackTrace 获取异常栈堆信息
  • printStackTrace 打印异常的堆栈信息

其他注意事项

  • 子类不能抛出比父类更大的异常,比如父类抛出NullPointException,那么子类不能抛出RuntimeException
  • 异常是可序列化的
  • 只有针对异常时才使用异常,因为业务中使用异常比正常代码要慢得多
  • 不要定义任何既不是受检异常也不是运行时异常的抛出类型。
  • 只有在底层方法的规范碰巧可以保证“它所抛出的所有异常对于更高层也是合适的”情况下,才可以将异常从低层传播到高层
  • 异常转译:更高层的实现应该捕获低层的异常,同时抛出可以按照高层抽象进行解释的异常
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值