断言 Assert Java关键字&Spring的用法

Java中的assert

关于Java断言

Java assert关键字允许开发人员快速验证程序的某些假设或状态。

Java assert关键字是在Java 1.4中引入的,所以它已经存在很长一段时间了。然而,它仍然是一个鲜为人知的关键字,它可以极大地减少样板文件并使我们的代码更具可读性。

例如,在我们的代码中,我们经常需要验证某些可能阻止应用程序正常工作的条件。通常我们会这样写:

Connection conn = getConnection();
if(conn == null) {
    throw new RuntimeException("Connection is null");
}

使用断言,我们可以用一个assert语句来代替if和throw语句。

启用Java的断言

因为Java断言使用assert关键字,所以不需要导入库或包。

注意,在Java 1.4之前,使用单词“assert”来命名变量、方法等是完全合法的。在使用较旧的代码和较新的JVM版本时,这可能会造成命名冲突。

因此,为了向后兼容性,JVM在默认情况下禁用断言验证。必须使用-enableassertions命令行参数或者它的简写-ea来显式地启用它们:

java -ea com.baeldung.assertion.Assertion

此时我们为所有类启用了断言。

我们还可以为特定的包和类启用断言:

java -ea:com.baeldung.assertion... com.baeldung.assertion.Assertion

在这里,我们为com.baeldung.assertion中的所有类启用了断言。

同样,可以使用*-disableassertions命令行参数或其简写-da*来禁用特定的包和类。我们也可以同时使用这四个参数。

使用Java断言

要添加断言,只需使用assert关键字并给它一个布尔条件:

public void setup() {
    Connection conn = getConnection();
    assert conn != null;
}

Java还为断言提供了第二种语法,它接受一个字符串。如果一个错误被抛出,它将用于构造AssertionError:

public void setup() {
    Connection conn = getConnection();
    assert conn != null : "Connection is null";
}

从代码可知,Assert断言的表达式基本分为两类

Assert.方法名 (布尔表达式) : 这类方法都标记过时, 都调用第二类方法
Assert.方法名 (布尔表达式,错误提示信息) : 这类方法, 如果布尔表达式不满足,会抛出异常,并将异常信息封装.

在这两种情况下,代码都在检查到外部资源的连接是否返回非空值。如果该值为null, JVM将自动抛出AssertionError。

在第二种情况下,异常将具有附加的细节,这些细节将显示在堆栈跟踪(stack trace)中,并可以帮助程序员调试问题。

让我们看看运行启用了断言的类的结果:

Exception in thread "main" java.lang.AssertionError: Connection is null
        at com.baeldung.assertion.Assertion.setup(Assertion.java:15)
        at com.baeldung.assertion.Assertion.main(Assertion.java:10)

AssertionError类继承了Error类,而Error类本身继承了Throwable。这意味着AssertionError是一个非检查的异常(unchecked exception)。

因此,使用断言的方法不需要声明它们,而且进一步的调用代码不应尝试捕捉抛出的AssertionError。

AssertionErrors用于指出在应用程序中不可恢复的出错情况,因此不要试图处理它们或尝试恢复。

总结

关于断言,要记住的最重要的一点是,它们是可以禁用的,所以永远不要假设它们会被执行。

因此,在使用断言时要记住以下几点:

· 在适当的时候,总是检查null值和空选项
· 避免使用断言检查public方法的输入,而是使用检查的异常,如IllegalArgumentException或NullPointerException
· 不要在断言条件中调用方法,而是将方法的结果赋给局部变量,并在断言中使用该变量
· 断言非常适合于代码中永远不会执行的地方,比如switch语句的默认情况(default case)或永远不会结束的循环之后
· assert不是一个仓促拼凑起来的宏,为了不在程序的Debug版本和Release版本引起差别,assert不应该产生任何副作用。所以assert不是函数,而是宏。程序员可以把assert看成一个在任何系统状态下都可以安全使用的无害测试手段。

Spring中的assert

Spring 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元素。

参考链接:
https://blog.csdn.net/neweastsun/article/details/80152756
https://zhuanlan.zhihu.com/p/265444322

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值