《代码整洁之道》——(6)错误处理
目录
6.1、使用异常而非错误码
6.2、先写Try-Catch-Finally语句
6.3、使用不可控异常
可控异常的代价就是违反开放/闭合原则。
6.4、给出异常发生的环境说明
你抛出的每个异常,都应当提供足够的环境说明,以便判断错误的来源和处所。在Java中,你可以从任何异常里得到堆栈踪迹(stack trace);然而,堆栈踪迹却无法告诉你该失败操作的初衷。
应创建信息充分的错误信息,并和异常一起传递出去。在消息中,包括失败的操作和失败类型。如果你的应用程序有日志系统,传递足够的信息给catch快,并记录下来。
6.5、依调用者需要定义异常类
将第三方API打包是个良好的实践手段。当你打包一个第三方API,你就降低了对它的依赖;未来你可以不太痛苦地改用其他代码库。在你测试自己的代码时,打包也有助于模拟第三方调用。
打包的好处还在于你不必绑死在某个特定厂商的API设计上。你可以定义自己感觉舒服的API。
6.6、定义常规流程
try{
MealExpenses expenses = expenseReportDAO.getMeals(emplyee.getID());
m_total += expenses.getTotal;
} catch(MealExpensesNotFoune e){
m_total += getMealPerDiem();
}
上面代码来自某个记账应用的开支总计模块,业务逻辑是,如果消耗了餐食,则计入总额中。如果没有消耗,则员工得到当日餐食补贴。异常打断了业务逻辑。如果不去处理特殊情况会不会好一些?
那样的话代码看起来会更简介。就想这样:
MealExpenses expenses = expenseReportDAO.getMeals(employee.getID());
m_total += expenses.getTotal();
能把代码写的那样简洁吗?能,可以修改ExpenseReportDAO,使其总是返回MealExpenses对象。如果没有餐食消耗,就返回一个返回餐食补贴的MealExpenses对象。
public class PerDiemMealExpenses implements MealExpense{
public int getTotal(){
// return the per diem default
}
}
这种手法叫做特例模式。 创建一个类或配置一个对象,用来处理特例。你来处理特例,客户代码就不用应付异常行为了。异常行为被封装到特例对象中。
6.7、别返回null值
返回null值,基本上就是给自己增加工作量,也是在给调用者添乱。只要一处没检查null值,应用程序就是失控。如果你打算在方法中返回null值,不如抛出异常,或是返回特例对象。
如果你在调用第三方API中可能返回null值的方法,可以考虑用新方法打包这个方法,在新方法中抛出异常或返回特例对象。
6.8、别传递null值
在方法中返回null值是糟糕的做法,但将null值传递给其他方法就更糟糕了。除非API要求你向它传递null值,否则就要尽可能避免传递null值。