Chapter 7: Error Handling
1-使用异常而不是返回错误码
之前讨论过,使用异常机制,会使得代码简洁清晰的多。
2-提供关于错误的信息
3-为调用的需求定义异常处理类
对比以下代码
ACMEPort port = new ACMEPort(12);
try {
port.open();
} catch (DeviceResponseException e) {
reportPortError(e);
logger.log("Device response exception", e);
} catch (ATM1212UnlockedException e) {
reportPortError(e);
logger.log("Unlock exception", e);
} catch (GMXError e) {
reportPortError(e);
logger.log("Device response exception");
} finally {
...
}
VS
// 假如 ACMEPort 是第三方API, 这样做可以降低与API的耦合
// 并且可以按照自己的思路设计代码的逻辑
LocalPort port = new LocalPort(12);
try {
port.open();
} catch (PortDeviceFailure e) {
reportError(e);
logger.log(e.getMessage(), e);
} finally {
...
}
// LocalPort 类,没错,就是专门为ACME写的
public class LocalPort {
private ACMEPort innerPort;
public LocalPort(int portNumber) {
innerPort = new ACMEPort(portNumber);
}
public void open() {
try {
innerPort.open();
} catch (DeviceResponseException e) {
throw new PortDeviceFailure(e);
} catch (ATM1212UnlockedException e) {
throw new PortDeviceFailure(e);
} catch (GMXError e) {
throw new PortDeviceFailure(e);
}
}
...
}
当且仅当你需要抓一些异常,但想放走其他异常的时候,才使用多种异常类型处理。
4-定义特殊情况处理
假如有这么一情况,在某商店,你买了书则免邮费,不买则需要付邮费10元。
// try catch扰乱了代码逻辑
try {
获取书费
总消费 += 书费
} catch(没买书 e) {
总消费 += 邮费
}
VS
获取书费
总消费 += 书费
// 设置特殊情况
当没买书时,"获取书费的函数返回邮费"
5-不要返回NULL!!!
假如获取员工列表
// 如果返回null
List<Employee> employees = getEmployees();
if (employees != null) {
for(Employee e : employees) {
totalPay += e.getPay();
}
}
// 如果不返回null,返回空list
List<Employee> employees = getEmployees();
for(Employee e : employees) {
totalPay += e.getPay();
}
最可怕的不是写判断 != NULL 很不整洁,而是我们可能忘了判断而导致运行时错误。
6-不要传NULL,除非函数要求!
同上,一样会出运行时错误。否则我们就要对所有函数的参数进行检验,然后对不合法的抛出异常。
7-总结
独立出你的异常处理!
clean 和 robust 并不矛盾!