本文收录于 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. day03-功能实现03

    功能实现03 9.功能08-分页显示 9.1需求分析 将查询的数据进行分页显示,要求功能如下: 显示共多少条记录 可以设置每页显示几条 点击第几页,显示对应的数据 9.2思路分析 后端使用MyBati ...

  2. day01-项目介绍+SSM环境搭建

    项目介绍+SSM环境搭建 1.项目功能/界面 SSM整合项目界面:使用Vue完成 技术栈:前后端分离开发,前端框架Vue3+后端框架SSM 前端框架-Vue3 后端框架-SSM(SpringMVC+S ...

  3. 关于linux系统版本的一个分类展现

    PS:要转载请注明出处,本人版权所有. PS: 这个只是基于<我自己>的理解, 如果和你的原则及想法相冲突,请谅解,勿喷. 前置说明   本文发布于 2014-07-06 22:58:35 ...

  4. 你是怎么处理vue项目中的错误的?

    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 一.错误类型 任何一个框架,对于错误的处理都是一种必备的能力 在Vue 中,则是定义了一套对应的错误处理规则给到使用者,且在源代码级别,对 ...

  5. 记录--这个前端Api管理方案会更好?

    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 简介 大家好,前端小白一枚,目前接触后台管理系统比较多,经常遇到不同对象的增删改查的接口,如何对Api进行一个有比较好的管理是个问题.在学 ...

  6. 记录--妙用computed拦截v-model,面试管都夸我细

    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 如何避免写出屎山,优雅的封装组件,在面试官面前大大加分,从这篇文章开始! 保持单向数据流 大家都知道vue是单项数据流的,子组件不能直接修 ...

  7. 记录--Vue自定义指令实现加载中效果v-load(不使用Vue.extend)

    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 网站效果演示:ashuai.work:8888/#/myLoad GitHub仓库地址代码:github.com/shuirongshu- ...

  8. API接口开发规范

    API接口是不同软件系统之间进行通信的重要方式,良好的API接口设计规范可以提高系统的可维护性.可扩展性和易用性.本文介绍了一套详细的API接口开发规范,包括命名规范.请求和响应规范.安全规范等内容, ...

  9. druid开启sql监控平台

    1.maven导入依赖 <dependency> <groupId>com.alibaba</groupId> <artifactId>druid< ...

  10. Modbus报文详解

    Modbus是一种串行通信协议,最初由Modicon公司(现为施耐德电气的一部分)在1979年为使用其PLC(可编程逻辑控制器)而开发.Modbus已成为工业领域内广泛使用的一种通信协议,特别是对于监 ...