实践 16:认识「异常控制流」 ( exception controlflow)机制
实践 17:绝对不可轻忽异常(Never ignoreanexception)
1. 提供LogException(),将异常信息写入文件,进行分析
2. 使用printStaticTrace()获取异常信息,进行分析
实践 18:千万不要遮掩异常( Never hide anexception)
实践 19:明察 throws子句的缺点
throws子句用来向函数调用者发出预警,告知将会产生哪些异常。
实践 20:细致而全面地理解throws子句
实践 21:使用finally 避免资源泄露( resourceleaks)
实践 22:不要从 try区段中返回
public class FinalTest {
public int method1() {
try{
return 2;
}
catch (Exception e) {
return 3;
}
}
public int method2() {
try{
return 3;
}
finally {
return 4;
}
}
public static void main(String[] args) {
FinalTest ft = new FinalTest();
System.out.println("method1 returns " + ft.method1());
System.out.println("method2 returns " + ft.method2());
}
}
method1 returns 2
method2 returns 4
实践 23:将 try/catch区段置于循环之外
在[启用JTM编译器]的情形下执行上述代码,两个函数的执行时间并没有什么不同。可是一旦你将JVM的JIT关闭再执行之, method2()大约比methodl()慢21%。
public class Excpef {
public void method1(int size) {
int[] ia = new int[size];
try {
for (int i = 0; i < size; i++) {
ia[i] = i;
}
}
catch (Exception e) {
}
}
public void method2(int size) {
int[] ia = new int[size];
for (int i = 0; i < size; i++) {
try {
ia[i] = i;
}
catch (Exception e) {
}
}
}
}
实践 24:不要将异常用于流程控制
实践25:不要每逢出错就使用异常( exceptions)
实践26:在构造函数(constructors)中抛出异常
尽管构造函数不是一般的函数,但他们仍然可以引发异常,并支持 throws语句。以这方式来构建失
败,是最强固、最高效的选择,从 class用户角度来看他要求的手工干预最小。
实践 27:抛出异常之前先将对象恢复为有效状态(valid state)
抛出异常是为了什么?明显的目的是将已发生的问题通知系统的其他部分。 隐含的目的则是让软件捕获异常,使系统有可能从问题中抽身回复(recover)而维持正常运行状态。
每当你撰写可能引发异常的代码时,都必须问自己: (1)异常发生之时(2)异常处理过后(3)复入(reentered)这段代码时,会发生什么事情?代码运转还能够正常吗?
import java.io.IOException;
class MutualFound1 {
public void buyMoreShares(double money) {}
}
class Customer1 {
private MutualFound1[] fundArray;
public Customer1(){}
public MutualFound1[] funds() {
return fundArray;
}
public void updateMutualFund(MutualFound1 fund) throws DatabaseException1 {}
public void writePortfolioChange() throws IOException {}
}
class DatabaseException1 extends Exception {}
public class ServiceClass1 {
public void invest(Customer1 cust, double money) throws DatabaseException1, IOException {
MutualFound1[] array = cust.funds(); //1
int size = array.length;
for (int i = 0; i < size; i++) {
array[i].buyMoreShares(money);
cust.updateMutualFund(array[i]); //2
cust.writePortfolioChange();
}
}
}
/*
* 问题:
假设某位客户在三个互惠基金中都拥有股票(shares), 并打算为每个基金各自再买进$1,000//l
取得了所有基金构成的 array,/ / 2 为 array 的第一笔基金购买$1,000,的股票,并通过
updateMutualFund()成功地将更新后的基金写入数据库。然后调用writePortfolioChange(),将某些信息写入文件。这时候这个函数失败了,因为磁盘空间不足,无法建立文件。于是在对第一
个MutualFund对象完成[完整的三个步骤]之前, 抛出一个异常, 意外而鲁莽地退出了invest ( )。
假设invest()调用者通过释放磁盘空间等于法,顺利处理了这个异常,而后再次调用invest()。
当invest()再次执行时,//l取得基金array,而后进入循环,为每支基金购买股票。但是不要
忘了,先前第一次调用invest()的时候,你已经为第一支基金购买了$1,000的股票。此时又再做
一遍。 如果这次invest () 顺利为客户的三笔基金完成了操作, 你就是为第一笔基金购买了$2,000,
而其他两支基金各购买$1,000,这是不正确的。显然不是你期望的结果。
就[首先释放磁盘空间,而后再次调用这个函数]的做法而言,你正确地处理了异常。你没有做的
是,在抛出异常之后、退出invest()之前,关注对象的状态。
*/
//===================refactor code==================================================//
/*
* 解决办法:
此问题的一个修正办法是,在MutualFund和Customer两个classes中添加函数,并在invest()
处理异常时调用它们。这些函数用来撤销未竞全功的一些事件。 Invest()必须增加catch区段,
处理任何被引发的异常。这些catch区段应该调用相应函数*重置(重新设定)对象状态,这么一
来如果这个函数下次再被调用,就可以正确执行了。
另一个需要考虑的问题是, 万一[回复函数]undoMutualFundUpdate()和sellShares()也失败了, 情况会
变得如何?如果要保持系统顺利运转,你也需要对付这些失败。的确,正如你所看到,在抛出异常的时
候保持对象处于有效状态,可能非常困难,需要采取措施。
*/
import java.io.IOException;
class MutualFound1 {
public void buyMoreShares(double money) {}
public void shellShares(double mondy){} //refactor part
}
class Customer1 {
private MutualFound1[] fundArray;
public Customer1(){}
public MutualFound1[] funds() {
return fundArray;
}
public void updateMutualFund(MutualFound1 fund) throws DatabaseException1 {}
public void undoMutualFundUpdate(MutualFound1 fund) {} //refactor part
public void writePortfolioChange() throws IOException {}
}
class DatabaseException1 extends Exception {}
public class ServiceClass1 {
public void invest(Customer1 cust, double money) throws DatabaseException1, IOException {
MutualFound1[] array = cust.funds();
int size = array.length;
for (int i = 0; i < size; i++) {
array[i].buyMoreShares(money);
try { //refactor part
cust.updateMutualFund(array[i]);
}catch (DatabaseException1 dbe) {
array[i].shellShares(money);
throw dbe;
}
try { //refactor part
cust.writePortfolioChange();
} catch (IOException ioe) {
array[i].shellShares(money);
cust.undoMutualFundUpdate(array[i]);
throw ioe;
}
}
}
}