这篇Java基础非常可#异常

异常分类

Java把异常当作对象来处理,并定义一个基类java.lang.Throwable作为所有异常的超类。
在这里插入图片描述

Throwable 可以用来表示任何可以作为异常抛出的类,分为两种: ErrorException。其中 Error 类层次结构描述了Java运行时系统内部错误和资源耗尽错误。Exception层次结构有分解为两个分支:一个分支派生于RuntimeException;另一个分支包含其他异常。

Java语言规范将派生于Error类RuntimeException类的所有异常称为非受查异常,所有其他的异常称为受查异常

受查异常 :需要用 try…catch… 语句捕获并进行处理,并且可以从异常中恢复;
非受查异常 :是程序运行时错误,例如除 0会引发 Arithmetic Exception,此时程序崩溃并且无法恢复。

声明受查异常

一个方法不仅需要告诉编译器将要返回什么值,还要告诉编译器有可能发生什么错误,因此方法应该在其首部声明所有可能抛出的异常。
例如,标准类库中提供的FileInputStream类的一个构造器的声明:

public FileInputStream(String name) throws FileNotFoundException{

这个声明表示这个构造器可能初始化一个新的FileInputStream对象,也可能抛出一个FileNotFoundException类对象。如果这个方法抛出了这样一个异常对象,运行时系统就会开始搜索异常处理器,以便知道如何处理异常对象。

总之,一个方法必须声明所有可能抛出的受查异常,而非受查异常要么不可控制(Error),要么就应该避免发生(RuntimeException)。除了声明异常之外,还可以捕获异常,这样会使异常不被抛到方法之外,也不需要throws规范。

异常处理

Java的异常处理本质上是抛出异常捕获异常

①抛出异常

要理解抛出异常,首先要明白什么是异常情形(ExceptionCondition),它是指阻止当前方法或作用域继续执行的问题。其次把异常情形和普通问题相区分,普通问题是指在当前环境下能得到足够的信息,总能处理这个错误。对于异常情形,已经无法继续下去了,因为在当前环境下无法获得必要的信息来解决问题,你所能做的就是从当前环境中跳出,并把问题提交给上一级环境,这就是抛出异常时所发生的事情。抛出异常后,会有几件事随之发生。首先,是像创建普通的java对象一样将使用new在堆上创建一个异常对象;然后,当前的执行路径(已经无法继续下去了)被终止,并且从当前环境中弹出对异常对象的引用。此时,异常处理机制接管程序,并开始寻找一个恰当的地方继续执行程序,这个恰当的地方就是异常处理程序或者异常处理器,它的任务是将程序从错误状态中恢复,以使程序要么换一种方式运行,要么继续运行下去。

举个简单的例子,假使我们创建了一个学生对象Student的一个引用stu,在调用的时候可能还没有初始化。所以在使用这个对象引用调用其他方法之前,要先对它进行检查,可以创建一个代表错误信息的对象,并且将它从当前环境中抛出,这样就把错误信息传播到更大的环境中。

if(stu == null){
    throw new NullPointerException();
}

②捕获异常

在方法抛出异常之后,运行时系统将转为寻找合适的异常处理器(exception
handler)。潜在的异常处理器是异常发生时依次存留在调用栈中的方法的集合。当异常处理器所能处理的异常类型与方法抛出的异常类型相符时,即为合适的异常处理器。运行时系统从发生异常的方法开始,依次回查调用栈中的方法,直至找到含有合适异常处理器的方法并执行。当运行时系统遍历调用栈而未找到合适的异常处理器,则运行时系统终止。同时,意味着Java程序的终止。

要捕获一个异常,必须设置try/catch语句块。例如:

try{
	InputStream in = new FileInputStream(filename);
}
catch(IOExcetion ie){
	System.out.println(ie.getMessage);
}

如果在try语句中任何代码块抛出一个在catch子句中说明的异常类或其父类,那么(1)程序将跳过try语句块的其余代码块,(2)程序将执行catch子句中处理器代码。

如果在try语句块中的代码没有抛出任何异常,那么程序跳过catch子句。

如果方法中的任何代码抛出了一个在catch子句中没有声明的异常类型,那么这个方法就会立刻退出

在try语句块中可以捕获多个异常类型,并对不同类型的异常做出不同的处理。

try{
	code that might throw exceptions
}
catch(FileNotFoundException e){
	emergency action for missing files
}
catch(UnknowHostException e){
	emergency action for unknown hosts
}
catch(IOException e){
	emergency action for all other I/O problems
}

假设多种异常的处理动作一样,就可以合并catch子句:

try{
	code that might throw exceptions
}
catch(FileNotFoundException | UnknowHostException e){
	emergency action for missing files and unknown hosts
}
catch(IOException e){
	emergency action for all other I/O problems
}

注意:
在多个catch子句声明的异常类型中,父类型异常类必须声明在子类型异常类之后。例如上面例子中,IOException是FileNotFoundException和UnknowHostException的父类。


欲获得对象的更多信息,可以使用:

e.getMessage();

得到详细的错误信息,或者使用

e.getClass().getName();

得到异常对象的实际类型。


当异常发生时,通常方法的执行将做一个陡峭的非线性的转向,它甚至会过早的导致方法返回。例如,如果一个方法打开了一个文件并关闭,然后退出,你不希望关闭文件的代码被异常处理机制旁路。finally关键字为处理这种意外而设计。

例如:

InputStream in = new FileInputStream(filename);
try{
	code that might throw exception
}
catch(IOException ie){
	show error message
}
finally{
	in.close();
}

finally块无论有没有异常抛出都会执行。如果抛出异常,即使没有catch子句匹配,finally也会执行。一个方法将从一个try/catch块返回到调用程序的任何时候,经过一个未捕获的异常或者是一个明确的返回语句,finally子句在方法返回之前仍将执行。这在关闭文件句柄和释放任何在方法开始时被分配的其他资源是很有用。

例如:

public static int f(int n){
	try{
		int r = n * n;
		return r;
	}
	finally{
		if(n == 2){
			return 0;
		}
	}
}

在以上方法中,如果调用f(2),那么try语句块的计算结果为r==4,并执行return语句。然而,在方法真正返回前,还要执行finally子句。finally子句将使得方法返回0,这个返回值覆盖了原始的返回值4.

异常链

异常链顾名思义就是将异常发生的原因一个传一个串起来,即把底层的异常信息传给上层,这样逐层抛出。 Java API文档中给出了一个简单的模型:

try {   
    lowLevelOp();   
} catch (LowLevelException le) {   
    throw (HighLevelException) new HighLevelException().initCause(le);   
}

当程序捕获到了一个底层异常,在处理部分选择了继续抛出一个更高级别的新异常给此方法的调用者。
这样异常的原因就会逐层传递。这样,位于高层的异常递归调用getCause()方法,就可以遍历各层的异常原因。
这就是Java异常链的原理。异常链的实际应用很少,发生异常时候逐层上抛不是个好注意,
上层拿到这些异常又能奈之何?而且异常逐层上抛会消耗大量资源, 因为要保存一个完整的异常链信息.

自定义异常类

在程序中,可能会遇到任何标准异常类都没有能够充分地描述清楚地问题。这种情况下,就需要创建自己地异常类。

自定义异常类需要做的就是定义一个派生于Exception的类,或者派生于Exception子类的类。例如定义一个派生于IOException的类,定义的类应该包含两个构造器,一个默认的构造器;另一个是带有详细描述信息的构造器。

class FileFormatException extends IOException{
	public FileFormatException(){}
	public FileFormatException(String s){
		super(s);
	}
}

本文参考文献:
① Java核心技术卷一(第十版)
Java入门之异常处理

写在最后:新手上路,如有问题,欢迎大家指出,给意见。如果这篇文章对你有帮助,麻烦帮忙点一下赞,你们小小的举动能给我无限大的动力。拒绝白嫖,从我做起,从现在做起。Thank you for watching!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值