首页 > 编程语言 >Java 断言 Assert 使用教程与最佳实践

Java 断言 Assert 使用教程与最佳实践

时间:2024-04-24 09:23:46浏览次数:16  
标签:assert 教程 Java 断言 list wdbyte Assert com

本文收录于 Github.com/niumoo/JavaNotes,Java 系列文档,数据结构与算法!
本文收录于网站:https://www.wdbyte.com/,我的公众号:程序猿阿朗

作为一个 Java 开发者,如果要问你 Java 中有哪些关键字,你可能会随口说出一串,如果问你 Java 有哪些最不常使用的关键字,或许你还能说出几个。但是 assert 关键字一定算是其中之一,或者,Java 写了几年,还没有用过 Java 的 assert 关键字。

这篇文章介绍 Java assert 的用法、最佳实践、特殊用法以及替代工具。

Java Assert 简介

Assert 中文我们一般称为断言,你可以理解为 “十分肯定地说” 。很多编程语言中都有断言,使用断言可以快速方便的验证程序中的某个假设条件或者状态是否成立,不成立则立即抛出异常。断言通常用于开发和测试阶段。

Java 中的断言使用 assert 关键字实现,但是因为 assert 在 Java 1.4 中才被引入,因此在 Java 1.4 之前,assert 并不是 Java 关键字,可能会被写成普通变量名。新版 Java 严格遵守向后兼容下,这可能也是 Java 默认禁用断言的原因之一,开启断言可以使用 -ea 参数手动启用。

java -ea YourClassName

启用和禁用断言

基于上述原因,Java 默认关闭了断言,手动开启断言可以使用 -ea 作为 JVM 参数启动 Java 程序。

-ea-enableassertions 命令的缩写。

java -ea AssertDemo

也可以使用 -ea:包路径 只为某些包开启断言,如为包 com.wdbyte 中的所有类开启断言支持。

-ea:com.wdbyte...

如果某些类库过于老旧,使用了 assert 作为变量名,为了正常运行, Java 也提供了对某些包禁用断言的参数。

-da:com.wdbyte...

-da-disableassertions 的缩写

Java 中使用断言

Java 中使用断言有两种语法。

方式1

assert boolExpression;

使用 assert 关键词紧跟给一个布尔条件进行断言判断,这种方式断言失败时,会抛出 java.lang.AssertionError 异常,但是没有具体的错误信息。

举例:

List<String> list = Arrays.asList("wdbyte", "com");
boolean result = list.remove("x");
assert result;

运行:

Exception in thread "main" java.lang.AssertionError
	at com.wdbyte.assert1.AssertDemo1.main(AssertDemo1.java:14)

方式2

assert boolExpression:msg;

这种方式报错时会把 msg 通过构造函数赋值给 AssertionError

举例:

assert result : "移除失败";

运行:

Exception in thread "main" java.lang.AssertionError: 移除失败
	at com.wdbyte.assert1.AssertDemo1.main(AssertDemo1.java:15)

Assert 最佳实践

切记 assert 断言是一种调试工具,用于在开发和测试阶段检查程序的某些假设是否为真,它是开发者的一个辅助工具,不应该对线上代码的运行产生任何影响。

使用断言时的最佳实践是确保它不会成为程序的常规执行流程的一部分,而是作为一种发现内部错误和验证程序假设的手段。在性能敏感或者资源受限的环境中,开应该在开发和测试阶段使用断言,然后在部署生产版本之前禁用它们。

适用场景

  1. 开发和测试阶段的临时检查

    还是要重复一次这个使用时机,首先因为 assert语句在生产环境下默认是禁用的,其次它可能会对性能产生影响,不应该被用作错误处理机制。在开发或调试期间,当你想要验证某个假设时,assert可以作为一种快速检查的方法。这些用法通常在代码达到稳定状态后被移除或替换为更健壮的错误处理机制。

  2. 单元测试

    使用断言对方法的执行结果进行判断,是单元测试中最为常用的操作。如果断言不通过,程序会立即抛出错误。良好的代码应该编写对应的单元测试,并且给出尽可能多的测试用例,断言通过可以保证程序的运行结果在预期之内。

  3. 存在隐含约束条件

    如何理解存在隐含约束条件,比如下面的代码示例中,代码中 else 部分默认 i%3 的余数为2,这种可以看做是一个隐含的约束条件。

    if (i % 3 == 0) {
        ...
    } else if (i % 3 == 1) {
        ...
    } else { // 此处,我们认为 (i % 3 == 2)
        ...
    }
    

    在这个例子中,当你本想通过注释来声明某个隐含的规则时,可以该改用断言。因此上述的 if 语句可以这样改写:

    if (i % 3 == 0) {
       ...
    } else if (i % 3 == 1) {
        ...
    } else {
        assert i % 3 == 2 : i;
        ...
    }
    

    注意:例子中在 i 为负数时断言会失败,这时余数是负的。

不适用场景

  1. 不要用作参数校验

    断言不应该用于参数校验,首先断言可能会被禁用,禁用时断言的语句不会被执行。其次,参数校验应该抛出对应的异常,如 NullPointerExceptionIllegalArgumentExceptionIndexOutOfBoundsException.

  2. 不要在断言中执行代码。

    因为断言可能会被禁用,如果代码依赖断言执行,那么可能不会被执行。如 assert list.remove("x");; 在断言禁用时,不会被执行,会造成程序运行结果异常。

    // assert list.remove("x") : "移除失败"; 不可取,可能不执行
    // 推荐下面的方式
    boolean result = list.remove("x");
    assert result : "移除失败";
    

Assert 进阶用法

编译阶段消除断言

在性能受限的设备中开发应用,我们可能会希望完全从类文件中剔除断言。虽然可以禁用断言,但是对于在生产环境中不需要的代码,我们还是想尽可能的删去,这样不仅减小了类文件的大小,而且可以在没有高质量即时编译器(JIT)的情况下,减少资源占用并提升运行时性能。

如果你有类似的需求,可以结合 if 在编译阶段消除断言。

static final boolean asserts = false; // 设置为 false 来消除断言

public static void main(String[] args) {
    List<String> list = Arrays.asList("wdbyte", "com");
    boolean result = list.remove("x");
    if (asserts) {
        assert result : "移除失败";
    }
}

因为 if (asserts) 永远为 false,在编译阶段就会被优化,反编译编译后的 class 可以发现断言部分代码已经不存在了。

List<String> list = Arrays.asList("wdbyte", "com");
boolean result = list.remove("x");

强制启用断言

如果某些关键系统希望在指定环境中不能禁用断言。下面的静态初始化示例可以实现这个强制条件。

static {
    boolean assertsEnabled = false;
    assert assertsEnabled = true; 
    if (!assertsEnabled) {
        throw new RuntimeException("必须启用断言!!!");
    }
}

替代开源库

在Java中,除了语言内置的assert关键字外,许多开源库都提供了更强大、更灵活的断言机制,这些工具通常用于单元测试中,但也可以用于生产代码中对条件进行验证。下面列出一些广泛使用的有断言功能的开源库。

  1. JUnit: JUnit是一个广泛使用的单元测试框架,其中包含用于编写测试断言的方法。JUnit 4 使用org.junit.Assert类提供断言,而JUnit 5 则引入了org.junit.jupiter.api.Assertions类。

    List<String> list = Arrays.asList("wdbyte", "com");
    boolean result = list.remove("x");
    Assertions.assertTrue(result);
    
  2. AssertJ: AssertJ 提供了丰富的、流式的、易于使用的断言库,使得错误的诊断更为容易。它支持Java 8的特性,比如lambda表达式、Stream和Optional类型的断言。

    Assertions.assertThat("").isEmpty()
    
  3. Apache Commons Lang : 提供的 Validate 类可以进行常见的条件验证。

    Validate.isTrue(list.isEmpty(),"msg");
    
  4. Google Guava :Guava 提供了 Preconditions 类可以用于常见的条件验证,还提供了一个 Verify 类用于断言操作。

    Preconditions.checkNotNull("","msg");
    Verify.verify(list.isEmpty(),"msg");
    

一如既往,文章中代码存放在 Github.com/niumoo/javaNotes.

参考

  1. https://docs.oracle.com/javase/8/docs/technotes/guides/language/assert.html
  2. https://junit.org/
  3. https://github.com/assertj/assertj

本文收录于 Github.com/niumoo/JavaNotes,Java 系列文档,数据结构与算法!
本文收录于网站:https://www.wdbyte.com/,我的公众号:程序猿阿朗

标签:assert,教程,Java,断言,list,wdbyte,Assert,com
From: https://www.cnblogs.com/niumoo/p/18154340

相关文章

  • 挑战前端基础120题--JavaScript 中如何实现链式调用的函数?
    一.何为链式调用?链式调用是一种简化过程的编码方式,使代码看起来更加简洁~它允许你通过在方法调用之间返回对象本身,从而连续地调用多个方法;比较常见的链式调用:jQuery,Promise等,通过多次书写.或()操作来调用。二.实现的原理?每次执行完成后返回自己/新的自己,这样可以确保后续的......
  • JavaImprove--Lesson10--IO流-字符流,缓冲流,转换流,打印流,数据流
    一.IO流-字符流上期在字节流的学习中,了解到字节流写字符操作表现很不好,随时面临乱码的情况,一下写完全部数据的,内存可能不足,所以对于文本操作还需要专业的操作 而字符流就非常适合操作文本字符FileWirte文件字符输入流作用:以内存为基准,可以把文件的数据以字符的形式输入到......
  • Java SE 笔记搬运
    本科过过两遍JavaSE,但是由于考研等不可抗力因素很久未接触代码,因工作需求这里将四年前的Java笔记重新整理搬运,方便Java学习。——————————————————————————————————————————————————————————————继承/*私有化的......
  • 详细分析Java中的@JsonFormat注解和@DateTimeFormat注解
    @DateTimeFormat(pattern="yyyy-MM-ddHH:mm:ss")@JsonFormat(pattern="yyyy-MM-ddHH:mm:ss",timezone="GMT+8")privateDatecreated_on;在前后端数据交互的过程中,Data类型的数据经常会出现类型映射转换的错误,为了达到业务的目标时间格式,通常会使用@JsonFormat和@DateTi......
  • Java并发工具类之LongAdder原理总结
    出处: Java并发工具类之LongAdder原理总结LongAdder实现原理图                                高并发下N多线程同时去操作一个变量会造成大量线程CAS失败,然后处于自旋状态,导致严重浪费CPU资源,降低了并发......
  • MyBatis所有的jdbcType类型对应的javaType类型
    来源:https://www.jb51.net/program/287517rew.htmMyBatis处理MySQL字段类型date与datetime1)DATETIME显示格式:yyyy-MM-ddHH:mm:ss时间范围:['1000-01-0100:00:00'到'9999-12-3123:59:59']2)DATE显示格式:yyyy-MM-dd时间范围:['1000-01-01'到'9999-12-31'......
  • windows server 2012 standard搭建onlyoffice服务所用软件和安装教程(亲测有效)
    链接内容:postgresql请使用12版本的,否则会报错!百度链接:https://pan.baidu.com/s/14PZJsjH-kqvKNZHjyBCWcA提取码:89zb效果:excel(xls)word(doc)......
  • cmd命令行运行Java文件产生乱码问题的解决方式
    1.第一种方式(改变记事本的编码集为ANSI)另存为ANSI 这样就OK啦2.第二种方式 改变cmd编码集 javac-encodingutf8 源文件名.java ......
  • 【JAVA】助力数字化营销:基于协同过滤算法实现个性化商品推荐
    ​​周松杰:碧桂园服务后台开发gao级工程师,拥有8年开发经验。1前言本文主要介绍基于协同过滤的推荐算法。在了解实践应用之前,我们先对推荐系统、Mahout学习框架以及算法进行简单介绍,然后再结合实践进行深入探讨。第一部分概述了推荐系统的产生背景、作用和工作原理,并介绍了Ma......
  • Java面试题:请谈谈Java中的volatile关键字?
    在Java中,volatile关键字是一种特殊的修饰符,用于确保多线程环境下的变量可见性和顺序性。当一个变量被声明为volatile时,它可以确保以下两点:内存可见性:当一个线程修改了一个volatile变量的值,其他线程会立即看到这个改变。这是因为volatile关键字会禁止CPU缓存和编译器优化,从而确......