assert是什么以及什么时候用assert

断言在软件开发中是一种常用的调试方式,很多开发语言中都支持这种机制。一般来说,断言用于保证程序最基本、关键的正确性。断言检查通常在开发和测试时开启。为了保证程序的执行效率,在软件发布后断言检查通常是关闭的。断言是一个包含布尔表达式的语句,在执行这个语句时假定该表达式为true;如果表达式的值为false,那么系统会报告一个AssertionError。断言的使用如下面的代码所示:

1
assert(a > 0); // throws an AssertionError if a <= 0
断言可以有两种形式:
assert Expression1;
assert Expression1 : Expression2 ;
Expression1 应该总是产生一个布尔值。
Expression2 可以是得出一个值的任意表达式;这个值用于生成显示更多调试信息的字符串消息。

要在运行时启用断言,可以在启动JVM时使用**-enableassertions或者-ea标记。**要在运行时选择禁用断言,可以在启动JVM时使用-da或者-disableassertions标记。要在系统类中启用或禁用断言,可使用-esa或-dsa标记。还可以在包的基础上启用或者禁用断言。

作用:

是用于对程序进行调试的,对于执行结构的判断,而不是对于业务流程的判断。(相当于一个if ()语句,如果满足断言的执行程序,如果不满足则抛错误)

使用情形:断言只适用复杂的调式过程。(如果不复杂完全可以用log或者debug代替)

特性:首先assert需要自行开启(jvm断言默认是关闭的,如何开启等会讲解),然后assert不具有继承性(父类禁止断言,子类可以开启断言)

语法:assert 直接加语句,但结果一定要是boolean类型

使用assert

①**、如何判断自己是否开启断言
原理:如果开启断言,则会调用断言语句。**

public static void main(String[] args) {
	// TODO Auto-generated method stub
	boolean isOk = false;
		
	assert isOk = true;//如果开启则会调用assert,那么isOk就为true
		
	System.out.println(isOk);//返回结果:false。一般结果都是返回false,表示assert未开启
}
③、作用:判断结果
public static void main(String[] args) {
	// TODO Auto-generated method stub
	boolean isRight = 1 > 2;
	assert isRight;//返回false则会报错,如果为true则继续执行程序<pre name="code" class="java">        System.out.println("程序正常");
}

④、自定义抛出的错误
public static void main(String[] args) {
	// TODO Auto-generated method stub
	boolean isRight = 1 > 2;
	assert isRight:"程序错误";//在:后写自定义的异常
	System.out.println("程序正常");
}

⑤、抛出的是error不是异常
public static void main(String[] args) {
	// TODO Auto-generated method stub
	boolean isRight = 1 > 2;
	try {
		assert isRight:"程序错误";//在:后写自定义的异常
		System.out.println("程序正常");
	} catch (Exception e) {
		// TODO: handle exception
		e.printStackTrace(e);//该行编译错误:提示没有异常需要抛出
	}
}
assert的错误是继承自error的,所以需要这样写:
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		boolean isRight = 1 > 2;
		try {
			assert isRight:"程序错误";//在:后写自定义的异常
			System.out.println("程序正常");
		} catch (AssertionError e) {
			// TODO: handle exception
			System.out.println(e.getMessage());//返回值:程序错误。(没错,这就是我们自定义的异常)
		}
	}

⑥、设置断言的使用范围

ea java -ea 打开所有用户类的assertion
-da java -da 关闭所有用户类的assertion
-ea: java -ea:MyClass1 打开MyClass1的assertion
-da: java -da: MyClass1 关闭MyClass1的assertion
-ea: java -ea:pkg1 打开pkg1包的assertion
-da: java -da:pkg1 关闭pkg1包的assertion
-ea:… java -ea:… 打开缺省包(无名包)的assertion
-da:… java -da:… 关闭缺省包(无名包)的assertion
-ea:… java -ea:pkg1… 打开pkg1包和其子包的assertion
-da:… java -da:pkg1… 关闭pkg1包和其子包的assertion
-esa java -esa 打开系统类的assertion
-dsa java -dsa 关闭系统类的assertion
综合使用 java -dsa:MyClass1:pkg1 关闭MyClass1和pkg1包的assertion

<think>嗯,用户现在问的是ASSERT宏或关键字的定义和使用场景。结合之前的对话历史,用户似乎是在学习编程中的调试和错误处理机制。之前讨论过自动运行时选择,现在转向断言,这很自然——都是开发中确保程序正确性的重要工具。用户可能正在编写或调试代码,遇到了需要验证程序假设的场景。ta的提问很专业,说明有一定编程基础,但可能对断言的具体实现细节和最佳实践不够清楚。需要重点解释清楚两点:ASSERT在开发阶段的防御性编程价值,以及和生产环境错误处理的区别。从技术角度看,ASSERT的核心是“程序员的良心检查工具”。要强调三个关键特性:只在调试模式生效、验证代码内部假设、避免被滥用处理用户输入错误。需要区分不同语言的实现差异——比如C/C++的宏机制、Python的__debug__内置变量、Java的类加载特性等。特别要注意用户引用的参考资料中提到了_Noreturn关键字[^1],这和ASSERT有潜在关联——某些编译器的断言失败处理会用到_Noreturn属性。但用户当前问题不需要深入这个细节,只需在脚注提一下即可。使用场景的说明要结合实际编程痛点。比如循环不变量的检查、函数前置条件验证,这些都是容易出bug的地方。示例代码最好展示经典用法:检查指针非空、数组索引有效等。同时必须警告常见误用——用ASSERT验证外部输入是绝对要避免的。最后生成的问题要引导用户深入理解断言机制:编译开关的影响、性能考量、与异常处理的互补关系。这些问题既能解决当前疑惑,也能帮助用户建立系统的调试思维。</think> ### ASSERT 宏的定义与使用场景 **ASSERT** 是编程中常用的**调试宏**,用于在开发阶段验证程序逻辑的正确性。当程序假设不成立时,ASSERT 会触发错误并终止程序,帮助开发者快速定位问题。 --- #### 一、核心定义与工作原理 ```cpp // 标准ASSERT宏定义(简化版) #ifdef NDEBUG #define ASSERT(condition) ((void)0) // 发布版:移除断言 #else #define ASSERT(condition) \ if(!(condition)) { \ std::cerr << "ASSERT failed: " #condition " in " << __FILE__ << ":" << __LINE__; \ std::abort(); \ } #endif ``` **工作机制**: 1. **调试模式**: - 若 `condition` 为 `false`,则打印文件名、行号和失败条件 - 调用 `abort()` 终止程序(部分实现会触发断点) 2. **发布模式**: - 通过 `NDEBUG` 宏将 `ASSERT(condition)` 替换为空操作 `(void)0` - **避免性能损耗**[^1] > ✅ 验证逻辑正确性,如 $x \geq 0$ 或指针非空: > ```cpp > void process(int* ptr) { > ASSERT(ptr != nullptr); // 断言指针非空 > // 后续操作 > } > ``` --- #### 二、主要使用场景 1. **前置条件检查** ```cpp int divide(int a, int b) { ASSERT(b != 0); // 确保除数非零 return a / b; } ``` 2. **循环不变量验证** ```python def binary_search(arr, target): low, high = 0, len(arr)-1 while low <= high: mid = (low+high)//2 # 断言索引始终有效 ASSERT(mid >= 0 and mid < len(arr)) if arr[mid] == target: return mid elif arr[mid] < target: low = mid+1 else: high = mid-1 ``` 3. **状态一致性检查** ```java public class Account { private double balance; public void withdraw(double amount) { balance -= amount; ASSERT(balance >= 0); // 确保余额不为负 } } ``` --- #### 三、关键注意事项 | **场景** | **正确做法** | **错误做法** | |--------------------|---------------------------------------|--------------------------| | 用户输入验证 | 使用异常处理(如 `try-catch`) | ❌ `ASSERT(input>0)` | | 第三方数据检查 | 返回错误码或日志警告 | ❌ `ASSERT(data != null)` | | 性能敏感代码 | 禁用断言(编译时定义 `NDEBUG`) | ❌ 在循环内频繁断言 | > **设计原则**: > - ASSERT 只用于捕获 **程序内部逻辑错误**(Bug) > - 不可替代运行时的错误处理机制 --- #### 四、跨语言实现差异 | **语言** | **断言机制** | **禁用方式** | |------------|------------------------------|-------------------| | C/C++ | `#include <cassert>` | `-DNDEBUG` 编译选项 | | Python | `assert condition, message` | `-O` 优化选项 | | Java | `assert condition : message` | `-da` JVM 参数 | | Rust | `debug_assert!(condition)` | `--release` 编译 | --- > **经典案例**: > 在快速排序中验证分区逻辑: > ```cpp > int partition(int arr[], int low, int high) { > int pivot = arr[high]; > int i = low - 1; > for (int j = low; j < high; j++) { > if (arr[j] < pivot) { > i++; > std::swap(arr[i], arr[j]); > } > } > std::swap(arr[i+1], arr[high]); > // 断言分区后左半部分<=pivot > for (int k = low; k <= i; k++) > ASSERT(arr[k] <= pivot); > return i+1; > } > ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值