天天看点

Spring的断言工具类Assert的基本使用Assert类目的

Assert使用场景

Web 应用在接受表单提交的数据后都需要对其进行合法性检查,如果表单数据不合法,请求将被驳回。类似的,当我们在编写类的方法时,也常常需要对方法入参进行合 法性检查,如果入参不符合要求,方法将通过抛出异常的方式拒绝后续处理。举一个例子:有一个根据文件名获取输入流的方法:InputStream getData(String file),为了使方法能够成功执行,必须保证 file 入参不能为 null 或空白字符,否则根本无须进行后继的处理。这时方法的编写者通常会在方法体的最前面编写一段对入参进行检测的代码,如下所示:

Spring Assert类帮助我们校验参数。通过使用Assert类方法,我们可以写出我们认为是正确的假设,反之,会抛出运行时异常。

public InputStream getData(String file) { 
    if (file == null || file.length() == 0|| file.replaceAll("\\s", "").length() == 0) {
        throw new IllegalArgumentException("file入参不是有效的文件地址"); 
    } 
… 
}
           

类似以上检测方法入参的代码是非常常见,但是在每个方法中都使用手工编写检测逻辑的方式并不是一个好主意。阅读 Spring 源码,您会发现 Spring 采用一个 org.springframework.util.Assert 通用类完成这一任务。

Assert类目的

每个Assert的方法可以与java assert表达式进行比较。java assert表达式在运行时如果条件校验失败,则抛出Error,有趣的是,这些断言可以被禁用。

Spring Assert的方法有一些特点:

  • 都是static方法
  • 抛出IllegalArgumentException 或 IllegalStateException异常
  • 第一个参数通常是需验证的对象或逻辑条件
  • 最后参数通常是异常消息,用于验证失败时显示
  • 消息可以作为String参数或Supplier 参数传输

尽管Spring Assert与其他框架的名称类似,如JUnit或其他框架,但其实没有任何共同之处。Spring Assert不是为了测试,而是为了调试。

使用示例

让我们定义Car类,并有public方法drive():

public class Car {
        private String state = "stop";

        public void drive(int speed) {
            Assert.isTrue(speed > 0, "speed must be positive");
            this.state = "drive";
            // ...
        }
    }
           

我们看到speed必须是正数,上面一行简短的代码用于检测条件,如果失败抛出异常:

if (!(speed > 0)) {
    throw new IllegalArgumentException("speed must be positive");
}
           

每个Assert的方法包含大概类似上面的条件代码块,校验失败抛出运行时异常,应用程序不期望恢复。

如果我们尝试带负数参数调用drive方法,会抛出IllegalArgumentException异常:

Exception in thread “main” java.lang.IllegalArgumentException: speed must be positive

逻辑断言

  • isTrue()

上面已经看到示例,其接受布尔条件,如果条件为假抛出IllegalArgumentException 异常。

  • state()

该方法与isTrue一样,但抛出IllegalStateException异常。

如名称所示,通常用在因对象的非法状态时,方法不能继续执行。假设骑车运行是不能加油,我们可以使用state方法断言:

public void fuel() {
        Assert.state(this.state.equals("stop"), "car must be stopped");
        // ...
    }
           

当然,我们能使用逻辑断言验证所有场景。但为了更好的可读性,我们可以使用其他的断言,使代码表达性更好。

对象和类型断言

  • notNull()

通过notNull()方法可以假设对象不null:

public void сhangeOil(String oil) {
        Assert.notNull(oil, "oil mustn't be null");
        // ...
    }
           
  • isNull()

另外一方面,我们能使用isNull()方法检查对象为null:

public void replaceBattery(CarBattery carBattery) {
        Assert.isNull(
          carBattery.getCharge(), 
          "to replace battery the charge must be null");
        // ...
    }
           
  • isInstanceOf()

使用isInstanceOf()方法检查对象必须为另一个特定类型的实例:

public void сhangeEngine(Engine engine) {
        Assert.isInstanceOf(ToyotaEngine.class, engine);
        // ...
    }
           

示例中,ToyotaEngine 是类 Engine的子类,所以检查通过.

  • isAssignable()

使用Assert.isAssignable()方法检查类型:

public void repairEngine(Engine engine) {
        Assert.isAssignable(Engine.class, ToyotaEngine.class);
        // ...
    }
           

这两个断言代表 is-a 关系.

文本断言

通常用来检查字符串参数。

  • hasLength()

如果检查字符串不是空符串,意味着至少包含一个空白,可以使用hasLength()方法:

public void startWithHasLength(String key) {
        Assert.hasLength(key, "key must not be null and must not the empty");
        // ...
    }
           
  • hasText()

我们能增强检查条件,字符串至少包含一个非空白字符,可以使用hasText()方法:

public void startWithHasText(String key) {
        Assert.hasText(
          key, 
          "key must not be null and must contain at least one non-whitespace  character");
        // ...
    }
           
  • doesNotContain()

我们能通过doesNotContain()方法检查参数不包含特定子串:

public void startWithNotContain(String key) {
        Assert.doesNotContain(key, "123", "key mustn't contain 123");
        // ...
    }
           

Collection和map断言

  • Collection应用notEmpty()

如其名称所示,notEmpty()方法断言collection不空,意味着不是null并包含至少一个元素:

public void repair(Collection<String> repairParts) {
        Assert.notEmpty(
          repairParts, 
          "collection of repairParts mustn't be empty");
        // ...
    }
           
  • map应用notEmpty()

同样的方法重载用于map,检查map不null,并至少包含一个entry(key,value键值对):

public void repair(Map<String, String> repairParts) {
        Assert.notEmpty(
          repairParts, 
          "map of repairParts mustn't be empty");
        // ...
    }
           

数组断言

  • notEmpty()

notEmpty()方法可以检查数组不null,且至少包括一个元素:

public void repair(String[] repairParts) {
        Assert.notEmpty(
          repairParts, 
          "array of repairParts mustn't be empty");
        // ...
    }
           
  • noNullElements()

noNullElements()方法确保数组不包含null元素:

public void repairWithNoNull(String[] repairParts) {
        Assert.noNullElements(
          repairParts, 
          "array of repairParts mustn't contain null elements");
        // ...
    }
           

注意,如果数组为空检查可以通过,只要没有null元素。

总结

我们浏览Assert类,在spring框架中应用广泛,充分利用它可以很容易写出强壮的代码。