错误处理很重要,但如果它搞乱了代码逻辑,就是错误的做法
整洁的代码中对错误的处理应当是被分离的关注点(不要跟正常的业务逻辑混杂在一起),而面向对象中的异常机制就是一种在不打乱原有业务逻辑的前提下处理掉程序在运行时发生的不正常状况的手段。
1.使用异常而非返回码
遇到错误时,最好抛出一个异常。调用代码很整洁,其逻辑不会被错误处理搞乱
- 以前,没有异常处理机制时:(这类手段的问题在于,他们搞乱了调用者代码。调用者必须在调用之后即刻检查错误,不幸的是,这个步骤很容易被遗忘。)
- 设置一个错误标识;
- 返回给调用者检查的错误码;
- 有异常处理机制后:(遇到错误时,最好抛出一个异常。调用代码很整洁,绮逻辑不会被错误处理搞乱。)
- 使用异常机制来处理错误。
2.先写Try-Catch-Finally语句
-
1.异常的妙处之一是,它们在程序中定义了一个范围。执行try-catch-finally语句中try部分的代码时,你是在表明可随时取消执行,并在catch语句中接续
-
2.在某种意义上,try代码块就像是事务,catch代码块将程序维持在一种持续状态
-
3.在编写可能抛出异常的代码时,最好先写try-catch-finally语句,能帮你定义代码的用户应该期待什么,无论try代码块中执行的代码出什么错都一样
3.使用不可控异常
可控异常的代价就是违反开放/闭合原则OCP,如果底层函数需要抛出新的可控异常,得在catch语句和抛出异常处之间的每个方法签名中声明该异常。
4.给出异常发生的环境说明
-
1.抛出的每个异常,都应当提供足够的环境说明,以便判断错误的来源和处所
-
2.应创建信息充分的错误消息,并和异常一起传递出去
5.依调用者需要定义异常类
将第三方API打包是个良好的实践手段,降低了对每个第三方的依赖,也有助于模拟第三方调用
举个例子(对某个第三方库代码的调用)
ACMEPort port = new ACMEPort(12);
try {
port.open();
} catch (DeviceResponseException e) {
reportPortError(e);
} catch (ATM1212UnlockedException e) {
reportPortError(e);
} catch (GMXError e) {
reportPortError(e);
} finally {
...
}
复制代码
以上代码包含了一大推重复代码,我们可以通过打包调用API,来确保他返回一个通用的异常
简单来说就是,因为上面那么多异常最后处理的代码都一样,我们可以把这么多个异常整合成一个异常:
ACMEPort port = new ACMEPort(12);
try {
port.open();
} catch (DeviceResponseException e) {
reportPortError(e);
} finally {
...
}
public class LocalPort {
private ACMEPort port;
public LocalPort(int number) {
port = new ACMEPort(number);
}
public void open() {
try {
port.open();
} catch (DeviceResponseException e) {
throw new PortDeviceFailure(e);
} catch (ATM1212UnlockedException e) {
throw new PortDeviceFailure(e);
} catch (GMXError e) {
throw new PortDeviceFailure(e);
} finally {
...
}
}
}
复制代码
再举个例子,假如我们项目中调用某一个第三方库,其中我们的项目使用程度涉及到几百个甚至更多的类。这时假如第三方库有==升级==或者我们使用的第三方库==有bug==或者与其它的库有冲突,此时要花很多时间。因此,我们可以把调用库的代码进行封装。
6.定义常规流程
特例模式(SPECIAL CASE PATTERN,[Fowler]),创建一个类或配置一个对象,用来处理特例,异常行为被封装到特例对象中
7.别返回null值
返回null值,基本是在给自己增加工作量 ,也是在给调用者添乱,只要有一处没检查null值,应用程序就会失控
与其返回null值,不如返回一个特例对象—空列表(Collections.emptyList())。议抛出异常或者返回特定对象(默认值)。
8.别传递null值
在方法中返回null值是糟糕的做法,但将null值传递给其他方法就更 糟糕了。
判断是否为null;
使用断言assert;
复制代码
看上去很美,单仍未解决问题。如果传入null值,还是会得到运行时错误。
在大多数编程语言中,没有良好的方法能对付由调用者意外传入的null值。
恰当的做法是,禁止传入null值。
我们可以加上注解@Nullable 和 @Nonnull来提示调用者,是否可以传入空值
复制代码
9.小结
将错误处理隔离看待,独立于主要逻辑之外,就能写出强固而整洁的代码
10.参考文献
《代码整洁之道》
blog.csdn.net/pengbo66656…
www.jianshu.com/p/c44eca6ad…
cloud.tencent.com/developer/a…
关注公众号“程序员面试之道”
回复“面试”获取面试一整套大礼包!!!
本公众号分享自己从程序员小白到经历春招秋招斩获10几个offer的面试笔试经验,其中包括【Java】、【操作系统】、【计算机网络】、【设计模式】、【数据结构与算法】、【大厂面经】、【数据库】期待你加入!!!