最近在完成公司的一个上报征信数据的项目,项目不大,因此开发人员就我一我的,可是工期挺紧,因此天天都写代码写到起飞。项目到尾期后,有一些闲暇能够 review 一下代码。结果发现,我全部的参数校验都是在 controller 层完成的,service 层没有校验。思索了一下,发现一个有趣的以前我没有主要到的事情。前端
controller 层校验后,能够经过返回字符串的形式,提示前端异常信息;service 校验后,须要返回 Exception 给上层。这会致使底层校验产生大量的自定义 Exception,但底层校验相比于顶层校验能辐射系统的更多部分,要想保持系统的健壮性,底层校验是必须的。那么因为底层校验致使上层代码涌现不少 try catch 怎么办?这些 try catch 还多是级联的,一层一层抛出去。java
service 层(这里举了 service 层的例子,实际上能够延伸到任何下层系统)可能抛出哪些异常?参数格式异常(好比要一段英文字符串,可是传入了数字字符串),业务逻辑异常(好比,数据重复或者找不到)。第一次想到这里的时候我脑壳里想的全是 checked 异常。可是灵光一闪,我发现 java 不是还有 unchecked 异常吗?编程
我们先思索一下,明确 checked 异常和 unchecked 异常的区别。checked 异常表示,这个异常的出现是正常的,容许的,因此你须要在编程阶段考虑它。unchecked 异常表示这个异常是不正常的,它的出现表示你的代码存在逻辑错误,因此你须要在编程阶段保证它在运行时不发生。编程语言
如今咱们有了两种异常定义的思路,一个是站在具体程序逻辑角度思考的(参数格式异常,业务逻辑异常),一个是站在编程语言角度思考的(checked 和 unchecked 异常)。学习
咱们来看看 java 本身是怎么作的。设计
从 java 的一些库的设计上来讲,一般参数的格式都做为一种协议,默认是你们都知道的,因此当格式错误的时候,程序抛出 unchecked 异常,你须要根据协议保证传入参数的正确性。java 有一个异常叫 IllegalArgumentException,它的出现表示“参数的前提条件不成立”,这个“前提条件”就是参数的协议。因为前提条件是经过文档等提早说明的,因此这是一种可预期异常(当你调用一个方法的时候,你就知道哪些错误的参数会致使异常发生)。接口
java 有例子能够来讲明 checked 异常,如 IOException,程序的 IO 必然和硬件打交道,而硬件并不像程序同样稳定,硬件可能掉电,可能因高温损坏,这些都是不可预期的,IOException 就能够用来表示与硬件交互过程当中发生的不可预期错误。因此 File 类中出现 IOException,Apache 的CloseableHttpClient 类中出现 IOException。开发
有了 java 的例子,咱们彷佛能够更清晰的辨识 service 应该如何抛出异常了。简单来讲,可预期的错误是 unchecked 的,不可预期错误是 checked 的。好比用户注册的 service 层方法,用户名,密码的格式异常是 unchecked 的,用户名已存在的异常是 checked 的。文档
如此,大量的参数控制逻辑,能够经过抛出一个 unchecked 的 IllegalArgumentException 来实现(向 java 学习),咱们也没必要为它们自定义异常类,上层也不会被它们困扰,上下层经过接口抽象来完成这种异常的处理。而另外一些不可预期的异常,咱们能够经过抛出自定义异常类的方式来表达错误发生了。因为剔除了参数校验的异常,这部分须要上层 try catch 的异常的数量就显得不是很可怕了,毕竟大多数业务逻辑可能根本不存在不可预期异常。字符串