上一篇关于异常处理的文章其实理解的不是特别清晰。现在的我在新的一轮查阅资料后,终于可以说是基本会用异常了。这里就单刀直入地直接下结论:

异常只在真正异常时使用,不应使用异常控制业务逻辑。

之所以能够如此坚定地得出这样的结论,是看了Stack Overflow上的一个问题1。在这个问题的回答中可以看到有人做了几组计算异常捕获的时间消耗的实验。

实验结论是,捕获Expection进行处理所需时间比正常业务流程控制多近两个数量级。我认为这已经是一个无法容忍的速度了。

之所以会这么慢,是因为引发异常需要收集堆栈跟踪信息。在Java中,引发异常的大部分开销是收集堆栈跟踪所花费的时间,这是在创建异常对象时发生的。引发异常的实际成本虽然很大,但却大大低于创建异常的成本。不过即便如此,引发异常也会造成比原先超出一个数量级的开销。

因此,如上篇文章所述,只有“用户死在了键盘上”这种超小概率事件,无法用编程避免的事件,才应该使用异常机制。

那要怎么做?

在实践中,由于很多情况是这样的,我们在正确执行的时候返回数据,错误的时候返回错误码,而之前使用异常的方式中,throw成为了函数的出口,而不是原路返回,所以能得到不同的返回值。在不使用异常机制的情况下,我们就需要修改代码。在不使用异常机制时,我们会封装业务逻辑层的处理结果,其中包含了状态码(代表执行情况),信息(简短的执行情况描述)以及数据(存放请求的内容)。

而我的做法是这样的,我直接使用了Java中的ResponseEntity类——因为最终从controller层发送出去的,也是包装好的这个类的对象。这个类可以定义返回的HTTP状态码,也可以自定义承载的内容,非常方便和好用。这样做的话就可以让controller层更加纯粹地干好接受请求调用业务逻辑的工作,实现业务逻辑分离。