系统异常可以分为两大类:业务类异常和技术类异常。顾名思义,业务类异常可以理解为在进行业务逻辑处理时,出现的异常。如创建客户订单时,发现没有为这个客户设置价格;取款时,取款金额大于帐户余额等。
技术类异常就更好理解了,这一层是与技术人员相关的,对系统使用者而言,应该是透明的。如无法正确连接数据库;访问数组或是列表时,索引超出范围;进行计算时,除数为零等。
针对不同类类型的异常,我们会采取不同的处理策略,请参照下表。
可预测异常 | 不可预测异常 | |
业务类异常 |
|
|
技术类异常 |
|
|
在讲异常重构之前,我们先看下面这段代码
public void writeFile(String fileName, String data) { FileWriter writer = null; writer = new FileWriter(fileName); writer.write(data); }
这样的写法是无法通编译的,因为在FileWriter的write方法定义的时候声明了抛出IOException异常,编译器要求我们必须在调用的地方处理这个异常。
public void writeFile(String fileName, String data) { FileWriter writer = null; try { writer = new FileWriter(fileName); writer.write(data); } catch (IOException e) { //todo } }
或是在我们自定义的方法头中明确声明此异常。
public void writeFile(String fileName, String data) throws IOException { FileWriter writer = null; writer = new FileWriter(fileName); writer.write(data); }
或是在调用的地方处理此异常。
对于第一种作法,我们并没有对异常进行作何处理,只是使用try catch语句捕获异常,并注明todo,待日后处理,但是时间一久,很容易就被遗忘了。有的小伙伴可能会说在catch语句中使用继续将该异常抛出
public void writeFile(String fileName, String data) { FileWriter writer = null; try { writer = new FileWriter(fileName); writer.write(data); } catch (IOException e) { throw e; } }
这样的做法不可取,因为这会让问题又回到了原点,在调用writeFile的函数中还是要处理我们抛出的异常呀!
第二种方法,和使用throw e异曲同工,同样是不处理异常,将其再次向外传递。
这时候就需要考虑对异常处理进行重构。我们先定义一个未处理的异常类。
/** * * @author Chris Mao(Zibing) * */ public class UnhandledException extends Exception { private Exception exception; private String message; /** * */ private static final long serialVersionUID = 3490319235806360289L; public UnhandledException(Exception e, String message) { this.exception = e; this.message = message; } public Exception getException() { return exception; } public String getMessage() { return message; } }
然后再将文章一开始提到的代码改为如下。
public void writeFile(String fileName, String data) throws UnhandledException { FileWriter writer = null; try { writer = new FileWriter(fileName); writer.write(data); } catch (IOException e) { throw new UnhandledException(e, "这个异常日后再说,先让业务功能跑起来"); } }
这样既可以达到快速开发的要求,又可以确保日后不会忘记对这个异常的处理。