JAVA学习日志4 异常处理 (Head First Java 190627)

11 篇文章 0 订阅

第十一章 异常处理

1. 异常处理

Java的异常处理(exception-handling)机制是个简捷、轻量化的执行期间例外状况处理方式,它让你能够将处理错误状况的程序代码摆在一个容易阅读的位置。我们可以通该方法的声明throw语句来得知该方法可能会出现的异常。

通常把有风险的程序代码放在try/catch块中,异常是一种exception类型的变量

try{
	//危险动作
} catch(Exception ex){
	//尝试恢复
}

方法可以抓住其他方法所抛出的异常。异常总是会丢回给调用方。会抛出异常的方法必须要声明它有可能会这么做。

// 有风险、会抛出异常的程序代码
public void takeRisk() throws BadException {
	if (abandonAllHope) {
		throw new BadException();
	}
}
// 调用该方法的程序代码
public void crossFingers() {
	try {
		anObject.takeRisk();
	} catch (BadException ex) {
		System.out.println("Aaargh!");
		ex.printStackTrace();  // 如果无法恢复,可以使用该方法列出有效信息
	}
}	

Exception类型

Exception
IOException
InterruptedException
RuntimeException*
ClassCastException
NullPointerException

RuntimeException被称为不检查异常,你可以自己抛出与抓住它们,但是没有这个必要,编译器也不管,因为大部分的RuntimeException都是因为程序逻辑问题,而不是你所无法预测或防止的方法出现的执行期失败状况。try/catch 是用来处理真正的异常,而不是你程序的逻辑错误,该块要做的是恢复的尝试,或者至少会列出错误信息。

要点

  • 方法可以再运行期间遇到问题时抛出异常

  • 异常时Exception类型的对象

  • 编译器不会注意RuntimeException类型的异常。RuntimeException不需要声明或被抱在try/catch的块中(然而你还是可以这么做)

  • 编译器所关心的是称为检查异常的异常。程序必须认识有异常可能的存在

  • 方法可以用throw关键词抛出异常对象:

    throw new FikeIsTooSmallException( );

  • 可能会抛出异常的方法必须声明成throw Exception

  • 如果程序调用了有声明会抛出异常的方法,就得要告诉编译器已经注意到这件事

  • 如果要处理异常状况,就把调用包在try/catch块中,并将异常处理/恢复程序放在catch块中

  • 如果不打算处理异常,还是可以正式地将异常给ducking来通过编译,后面会解释ducking

finally
finally块是用来存放不管有没有异常都得执行的程序。

try {
	turnOverOn();
	x.bake();
} catch(BaikingException ex) {
	ex.printStackTrace();
} finally {
	turnOverOff();     //无论如何成功与否都会执行
}

即使try或者catch块中有return指令,finally还是会执行,流程会跳到finally执行后再回到return指令。

2. 多态的异常

如果有必要的话,方法可以抛出多个异常,例如:

public class Laundry {
	public void doLaundry() throw PantsException, LingerieException {
		...
	}
}

public class Foo {
	public void go() {
		Laundry laundry = new Laundry();
		try {
			laundry.doLaundry();
		} catch(PantsException pex) {
			... //恢复代码
		} catch(LingerieException lex) {
			... //恢复代码
		}
	}
}

因为异常时对象,所有异常也是有多态的,它也存在父类和子类。例如ClothingException就为PantsException、LingerieException和ShirtException的父类,而ShirtException又可以为TeeShirtException和DressShirtException的父类。

  1. 以异常的父类来声明会抛出的异常
public void doLaundry() throw ClothingException {
	...
}
  1. 以所抛出的异常父类来catch异常
try {
	laundry.doLaundry();
} catch(TeeShirtException tex) {  //子类异常1
	// solution
} catch(LingerieException lex) {  //子类异常2
	// solution
} catch(ClothingException cex) {  //父类异常
	// solution
}

顺序要注意,越下级的子类应放在最上面,父类放在下面

因为Java虚拟机只会从头开始往下找到第一个符合范围的异常处理块。如果父类放在上面,所有的异常都会在catch父类被执行。另外同级子类异常的先后顺序无所谓,因为它们的异常是不同的。

3. 声明(Duck)

如果不想处理异常的话,可以把它duck掉来避开。Duck其实就是把异常一次又一次丢给方法调用方,最后到main()中。

public class Washer {
	Laundry laundry = new Laundry();
	public void foo() throw ClothingException {
		laundry.doLaundry();
	}
	public static void main (String[] args) throw ClothingException {
		Washer a = new Washer();
		a.foo();
	}
}

在这里插入图片描述
两种满足编译器的有风险调用方式

  1. 处理
try {
	laundry.doLaundry();
} catch(ClothingException ex) {
	// solution
}
  1. 声明(duck)
public class Washer {
	Laundry laundry = new Laundry();
	public void foo() throw ClothingException {  //把异常留给调用方foo()
		laundry.doLaundry();
	}
	public static void main (String[] args) throw ClothingException {
	//把异常扔给main(),这里也要声明,如果这里没有throw,将无法进行编译	
		Washer a = new Washer();     
		a.foo();
	}
}

要么全部声明,要么处理异常

4. 异常处理规则

  1. catch与finally不能没有try
void go() {
	Foo f = new Foo();
	f.foof();       //缺少了try,无法编译
	catch(FoofException ex) {
	}
}
  1. try与catch之间不能有别的程序
try {
	x.doStuff();
	}
	int y = 43;       //这里不能放别的代码
	catch(Exception ex){}
  1. try一定要有finally或者catch
try {
	x.doStuff();
} finally {
	...
}          //合法程序
  1. 只带有finally的try必须要声明异常
void go() throw FooException {
	try {
		x.doStuff();
	} finally {
		...
	}
}          //没有catch的话必须进行声明
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值