本文收录于 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/,我的公众号:程序猿阿朗

Java 断言 Assert 使用教程与最佳实践的更多相关文章

  1. attilax.java 注解的本质and 使用最佳实践(3)O7

    attilax.java 注解的本质and 使用最佳实践(3)O7 1. 定义pojo 1 2. 建立注解By eclipse tps 1 3. 注解参数的可支持数据类型: 2 4. 注解处理器 2 ...

  2. paip.java win程序迁移linux的最佳实践

    paip.java win程序迁移linux的最佳实践 1.class load路径的问题... windows哈第一的从calsses目录加载,,而linux优先从jar加载.. 特别的是修理了ja ...

  3. 【转】Java中关于异常处理的十个最佳实践

    原文地址:http://www.searchsoa.com.cn/showcontent_71960.htm 导读:异常处理是书写强健Java应用的一个重要部分,Java许你创建新的异常,并通过使用 ...

  4. K:java 断言 assert 初步使用:断言开启、断言使用

    @转自天地悠悠的个人博客 主要总结一下在eclipse中如何使用断言. (一)首先明确: java断言Assert是jdk1.4引入的. jvm 断言默认是关闭的. 断言是可以局部开启的,如:父类禁止 ...

  5. java断言assert初步使用:断言开启、断言使用

    1 说明 java断言assert是jdk1.4引入的. jvm断言默认是关闭的. 断言可以局部开启的,如:父类禁止断言,而子类开启断言,所以一般说“断言不具有继承性”. 断言只适用复杂的调式过程. ...

  6. 01 java断言assert初步使用:断言开启、断言使用

    参考文件:http://blog.sina.com.cn/s/blog_59c9412d0100fd55.html 1 说明 java断言assert是jdk1.4引入的. jvm断言默认是关闭的. ...

  7. Java断言assert

    public class Welcome{ public static void main(String[] args){ assert false; System.out.println(" ...

  8. EffectiveTensorflow:Tensorflow 教程和最佳实践

    Tensorflow和其他数字计算库(如numpy)之间最明显的区别在于Tensorflow中的操作是符号. 这是一个强大的概念,允许Tensorflow进行所有类型的事情(例如自动区分),这些命令式 ...

  9. Java日志体系(八)最佳实践

    java常用日志框架关系 Log4j 2与Log4j 1发生了很大的变化,Log4j 2不兼容Log4j 1. Logback必须配合Slf4j使用.由于Logback和Slf4j是同一个作者,其兼容 ...

  10. Java对象拷贝原理剖析及最佳实践

    作者:宁海翔 1 前言 对象拷贝,是我们在开发过程中,绕不开的过程,既存在于Po.Dto.Do.Vo各个表现层数据的转换,也存在于系统交互如序列化.反序列化. Java对象拷贝分为深拷贝和浅拷贝,目前 ...

随机推荐

  1. CloudXR技术如何运用于农业?

    随着科技的不断发展和应用的深入,农业领域也在逐渐引入新技术来优化生产效率和成本.改进管理和监控等.云化XR(CloudXR)作为一种融合了云计算.虚拟现实(VR)和增强现实(AR)等技术的解决方案,也 ...

  2. 剖析云流送技术如何为3D应用带来用户使用便利

    在过去的十年中,云游戏技术的发展为云计算行业带来了新的机遇.随着Google Stadia和GeForce Now之类的服务逐步向公众开放,云流送(cloud streaming)技术得到更大范围的应 ...

  3. 网页端实现Excel转JSON

    1. 引言 有时工作中拿到的数据是Excel表格,要在前端网页上使用,通常需要把文件转为JSON 微软的Microsoft Excel没有导出为JSON的功能,其他的第三方网站又不太信任 开源的Exc ...

  4. IDEA 2019.3 plugins 插件搜索不出结果

    proxy的url输入: http://127.0.0.1:1080 重启idea即可

  5. C++常见面试题整理

    1. CPP编译链接过程 2. new和malloc区别,delete和free区别 3. 指针和引用 4. 左值引用和右值引用 5. const 6. 函数重载 7. 函数调用栈帧开辟过程 8. i ...

  6. Involution:空间不共享?可完全替代卷积的高性能算子 | CVPR 2021

    其实这篇文章很早就写好了,但作者其它论文涉及到洗稿问题,所以先放着了.目前看这篇文章没被举报有洗稿的嫌疑,所以就发出来了 . 来源:晓飞的算法工程笔记 公众号 论文: Involution: Inve ...

  7. KingbaseES索引坏块

    错误信息产生: 下面的报错一般为有坏块的产生. test=# select max(create_time) from public.tbl_table where create_time>=' ...

  8. LCD - 液晶显示原理(一)

    1. 显示器介绍 ​ 显示器属于计算机的I/O设备,即输入输出设备.它是一种将特定电子信息输出到屏幕上再反射到人眼的显示工具.常见的有CRT显示器.液晶显示器. LED点阵显示器及OLED显示器. 液 ...

  9. 冒泡排序【Java】

    1 public class Paixu { 2 public static void main(String args[]) { 3 int myNum[] = {2,6,4,1,5}; 4 //从 ...

  10. Java读取excel文件(.xlsx/.xls)和.csv文件存入MySQL数据库

    1 package com.reliable.service; 2 3 import com.csvreader.CsvReader; 4 import com.reliable.bean.FileD ...