异常(Exception)

Java学习笔记——异常(Exception)

异常的分类

img

Throwable类

Throwable:全部异常都是由Throwable继承而来的,能够经过继承Throwable来实现新的异常,可是通常不推荐这样作,下一层分为了两个分支:ErrorExceptionjava

Error类

Error类来用描述java运行时系统内部引发的错误和资源消耗错误,由于是java内部的错误,所以编写的应用程序无能为力。数组

Exception类

Exception:Exception类又能够分为IOExceptionRuntimeException,通常程序应该经过检测的方式尽可能避免RuntimeException(也就是说出现这种异常就是编写者本身的问题编写者无须要捕获这一类异常,相反,应该使用代码if(obj == null)检测避免出现NullPointExceptionide

RuntimeException类

RuntimeException:通常包括:学习

  • 错误的强制类型转换:ClassCastException
  • 数组访问越界:ArrayIndexOutOfBoundsException
  • 访问null指针:NullPointerException

IOException类

常见的IOException类通常包括:‘this

文件末尾继续读取数据:EOFException线程

试图打开一个不存在的文件:FileNotFoundException设计

根据给定的字符串查找class对象,可是该类不存在:ClassNotFoundException指针

...code

官方分类

Java通常把派生于Error类和RuntimeException类的异常称之为非检查型异常,而IOException称之为检查型异常orm

然而实际中,咱们可以进行处理的只有检查型异常,由于检查型异常在咱们我的的控制以内,非检查型异常对于任何的代码都有可能抛出,出现这些异常的时候咱们无法控制。

举个例子:任何获取对象引用的方法,都有可能获取对象引用失败而返回一个NullPointerException,这异常的出现是无法控制的,除非你给每个GetXX()方法都加上异常处理,可是这并不现实,所以不必处理非检查型异常。

抛出异常

声明检查型异常

如何声明检查型异常

以下:

public FileInputStream(String name) throws FileNotFoundException

若要声明多个检查型异常,则须要用逗号分割

public Image loadImage(String name) throws FileNotFoundException, EOFException

注意这里特别强调声明检查型异常,对于抛出非检查型异常通常是不须要声明的

何时须要声明

两种状况:

  1. 调用一个抛出检查型异常的方法的时候,传递异常的抛出,例如调用loadImage方法
  2. 方法自己须要抛出检查型异常
// situation 1
public Image loadNewImage(String name) throws FileNotFoundException, EOFException{
	loadImage(name);
}

// situation 2
public Image importFile(String name) throws FileNotFoundException{
	file f = readfile(name);
	if(f == null){
		throw new FileNotFoundException();	// 抛出异常
	}
}

抛出异常

抛出异常的方法:

// method 1:
throw new EOFException(); // 抛出一个EOFException

// method 2:
var a = new EOFException();
throw a;					// 抛出一个EOFException

通常怎样决定抛出异常呢?一般考虑的状况是这样:

  1. 找到一个合适的异常类
  2. 建立这一个异常类的对象
  3. 将对象抛出

一旦抛出异常以后,这个方法不会返回到调用者,也就是说无须要另外建议一个返回语句(return)

捕获异常

捕获异常

抛出检查型异常以后,若是没有对他进行捕获,当前执行的线程都会终止,那么如何捕获异常?

try{
	// 先执行try里面的语句
	// 一旦try里面的有一条语句抛出ExceptionTypeX类型异常,则进入相应的catch语句,终止以后的try代码块的执行
}catch(ExceptionType1 e){
	// 在这里处理异常
}catch(ExceptionType2 e){
	// 能够捕获多个异常
}catch(ExceptionType3 | ExceptionType4 e){
	// 若是抛出的两个异常是不一样的,可是他们的处理方法都同样的话,还能够这样捕获
	// 注意这种方式捕获异常时,变量e被隐式声明为final,所以不能改变e的值
}
}finally{
	// 不管是否发生异常,最后都会运行此处的代码,一般用于释放资源
	// finally代码块能够省略
	// 注意不要把控制流的语句放在finally(return,throw,break,continue),由于会发生意想不到的错误
	// 同时也不该该过度依赖finally,通常的设计原则是将finally应用在关闭资源或者释放资源,如关闭IO流等
}

捕获异常仍是传递异常

咱们能够经过捕获异常来处理方法抛出的异常,可是并不是每个异常咱们都知道怎么去处理,那要如何解决?

咱们知道一个方法调用方法A,方法A会调用另一个可能抛出异常的方法B时,咱们能够经过在方法A中声明检查型异常的方式,来将方法B中的异常传递给调用了方法A的那一个方法(说得更加直白一点就是A方法将B方法抛给A的异常再次抛出给A的调用者),让它来解决这一个异常,所以对于上面的问题,咱们就能够采用这种方式来解决,相似于下面的解决方式。

public A() throws Exception {
	B();
}
public B() throws Exception {
	... // 处理代码
	if(...){
		throw new Exception();
	}
}

public fun(){
	try{
		A();
	}catch(Exception e){
	  // do something
	}
}

实际上对于应该捕获异常仍是传递异常这一个问题,最好的答案是除非你知道怎么解决,不然就应该什么都不作,将异常传递给最终的调用者,让最终调用者来处理这个问题是最好不过的。

不过这种解决方案有一个例外:这个例外体如今继承特性上:

若是一个子类覆盖了超类的一个方法,那么子类要么不抛出异常,要么抛出的异常必须是超类异常的子类(也就是说子类须要抛出更加具体的异常),一样,若是覆盖的超类方法没有抛出异常,那么子类的覆盖方法也不能抛出异常。

所以,若是覆盖的超类方法没有抛出异常,而子类的覆盖方法又调用了其余可能抛出异常的方法,这种时候就必须在覆盖方法中捕获全部的异常。

自定义异常类

一般咱们须要知足咱们我的的一个程序须要的时候就须要自定义异常类,异常类的定义能够经过派生任何Exception类或者它的子类如IOException类来完成

public FileFormatException extends IOException
{
	public FileFormatException(){}
	public FileFormatException(String gride){
		super(gride);
	}
}
// 这样就能够完成本身的异常的定义了

异常链与异常再次包装

异常嵌套

先看下面的代码:

InputStream i = ...;
try{
 ...	// code 1
 	try{
 		// code 2
 	}catch(Exception e){
 	
 	}finally{
 		i.close();	
 	}
}catch(IOException e){

}

若finally中发生异常,则交由外层捕获处理,若code 2位置发生异常,交由内层处理

再次抛出异常

不少时候咱们不知道须要具体抛出一个什么异常,或者抛出去的异常可能带有选择性等状况,这时候就须要再次抛出新的子类异常,相似于下面的状况

try{

}catch(IOException e){
	throw new FileNotFoundException();
}

包装技术

对于再次抛出异常,如何防止原父类异常中的信息丢失?

try{

}catch(IOException e){
	var a  = new FileNotFoundException();
	a.initCause(e);
	throw a;
}

捕获异常时,使用

Throwable original = a.getcause();

就能够获取高层原始异常信息了。

包装技术很是有用,能够将多种异常包装成一类异常抛出,同时保留高层原始异常的信息。

try-with-resource语句

该语句用于简化try-catch-finally语句中的释放工做

要使用try-with-resource语句,须要res实现AutoCloseable接口,该接口只有一个方法

void close() throws Exception
try(Resource res = ...){
	// work
}

使用try-with-resource,代码段在运行结束以后,不管是否有异常抛出,都会调用res中实现的close()

通常状况下,只要须要关闭资源,就要尽量使用try-with-resource

异常类相关方法

java.lang.Throwable

Throwable()										// 构造一个新的Throwable对象,但没有详细的描述信息
Throwable(String message)						// 构造一个新的Throwable对象,带有详细的描述信息
String getMessage()								// 获取Throwable对象的详细描述信息

// 一般用于包装的构造方法
Throwable(Throwable cause)						// 用给定的cause(缘由)构造来构造Throwable对象
Throwable(String message, Throwable cause)		// 用给定的cause(缘由)构造和描述信息来构造Throwable对象
Throwable initCause(Throwable cause)			// 为这个对象设置缘由,若是对象已有缘由则抛出异常,返回this
Throwable getCause()							// 获取这个对象所设置的缘由,若是没有返回null

java.lang.Exception

Exception(Throwable cause)
Exception(String message, Throwable cause)		// 用给定的cause(缘由)来构建Exception对象
相关文章
相关标签/搜索