断言和异常

断言是用来检查非法情况而不是错误情况的,用来帮开发者快速定位问题的位置。
异常处理用于对程序发生异常情况的处理,增强程序的健壮性和容错性。

断言和Spring Validation验证框架作用类型,都在避免错误的参数影响程序运行,增强程序的健壮性,断言一般用在程序内部,而Spring Validation验证框架则经常用在控制器接受参数的校验。

1.断言是什么

在防御式编程中经常会用断言(Assertion)对参数和环境做出判断,避免程序因不当的输入或错误的环境而产生逻辑异常,断言在很多语言中都存在,C、C++、Python都有不同的断言表示形式。在Java中的断言使用的是assert关键字,其基本的用法如下:

assert <布尔表达式>
assert <布尔表达式> : <错误信息>

2. 断言的特性

  1. assert默认是不启用的
  2. assert抛出的异常AssertionError是继承自Error的

3. 使用assert的三种情况

a. 在私有方法中放置assert作为输入参数的校验

在私有方法中可以放置assert校验输入参数,因为私有方法的使用者是作者自己,私有方法的调用者和被调用者之间是一种弱契约关系,或者说没有契约关系,其间的约束是依靠作者自己控制的,因此加上assert可以更好地预防自己犯错,或者无意的程序犯错。

b. 流程控制中不可能达到的区域

这类似于JUnit的fail方法,其标志性的意义就是:程序执行到这里就是错误的,例如:

  1. public void doSomething(){
  2. int i = 7;
  3. while(i >7){
  4. /*业务处理*/
  5. }
  6. assert false:"到达这里就表示错误";
  7. }

c. 建立程序探针

我们可能会在一段程序中定义两个变量,分别代表两个不同的业务含义,但是两者有固定的关系,例如var1=var2*2,那我们就可以在程序中到处设“桩”,断言这两者的关系,如果不满足即表明程序已经出现了异常,业务也就没有必要运行下去了。

4. 断言方法说明

(1) notNull(Object object)

当 object 不为 null 时抛出异常,notNull(Object object, String message) 方法允许您通过 message 定制异常信息。和 notNull() 方法断言规则相反的方法是 isNull(Object object)/isNull(Object object, String message),它要求入参一定是 null;

(2) isTrue(boolean expression) / isTrue(boolean expression, String message)

当 expression 不为 true 抛出异常;

(3)notEmpty(Collection collection) / notEmpty(Collection collection, String message)

当集合未包含元素时抛出异常,既包含Map 和 Object[] 类型类型。

(4)hasLength(String text) / hasLength(String text, String message)

当 text 为 null 或长度为 0 时抛出异常;

(5)hasText(String text) / hasText(String text, String message)

text 不能为 null 且必须至少包含一个非空格的字符,否则抛出异常;

(6) isInstanceOf(Class clazz, Object obj) / isInstanceOf(Class type, Object obj, String message)

如果 obj 不能被正确造型为 clazz 指定的类将抛出异常;

(7) isAssignable(Class superType, Class subType) / isAssignable(Class superType, Class subType, String message)

subType 必须可以按类型匹配于 superType,否则将抛出异常;

5. 示例

使用 Assert 断言类可以简化方法入参检测的代码,如 InputStream getData(String file) 在应用 Assert 断言类后,其代码可以简化为以下的形式:
  1. public InputStream getData(String file){
  2. // 使用 Spring 断言类进行方法入参检测,不符合的抛出错误
  3. Assert.hasText(file,"file入参不是有效的文件地址");
  4. /*业务逻辑*/
  5. }