【0】README
0.1) 本文描述+源代码均 转自 core java volume 1, 旨在理解 java断言——Assertion 的相关知识;
【1】使用断言
1.1)断言机制: 允许在测试期间向代码中插入一些检查语句。 当代码发布时, 这些插入的检测语句将被自动地移走;
- 1.1.1)java 引入了 关键字assert, 有两种形式:
assert 条件; 和 assert 条件:表达式; - 1.1.2)以上两种形式 都会对条件进行检测: 如果结果为 false, 则抛出一个 AssertionException异常, 在第二种形式中, 表达式将被传入 AssertionError 的构造器中,并转换成一个 消息字符串;
Annotation)
- A1)表达式部分的唯一目的是产生一个消息字符串;
- A2) AssertionError 对象并不存储表达式的值, 因此,不可能在以后得到它;
- A3)如JDK 所说, 如果使用表达式的值, 就会鼓励coders 试图从断言中恢复程序的执行, 这不符合断言机制的初衷;
1.2)看个荔枝:
- 1.2.1)要想断言x 是一个 非负数值, 只需要简单地使用下面这条语句:assert x >=0;
- 1.2.2)或者:将 x 的实际值传递给 AssertionError 对象, 从而可以在后面显示出来, assert x >=0 : x; (因为x 将被传入AssertionError 构造器, 并转换为一个消息字符串)
【2】启用和禁用断言
2.1)默认情况下, 断言被禁用。可以在运行程序时用 -enableassertions 或-ea 选项启用它:
java -enableassertions MyApp
- 2.1.1)需要注意的是: 在启用或禁用断言时不必重新编译程序。启用和禁用断言是类加载器的功能, 当断言被禁用时, 类加载器将跳过断言代码, 因此,不会降低程序运行的速度;
- 2.1.2)也可以在某个类或某个包中使用断言: 如, java -ea:MyClass -ea:com.mycompany.lib … MyApp
- 2.1.3)也可以使用选项 -disableassertions 或 -da 禁用某个特定类和包的断言: java -ea:… -da:MyClass MyApp
Attention)
- A1)有些类不是由类加载器加载, 而是直接由虚拟机加载。 可以使用这些开关有选择地启用或禁用那些类中的断言;
- A2)然而, 启用和禁用所有断言的 -ea 和 -da 开关不能应用到那些没有类加载器的系统类上; 对于这些系统类来说, 需要使用 -enablesystemassertions/-esa 开关来启用断言;
【3】使用断言完成参数检查
3.1)在java中, 给出了 3种处理系统错误的机制(Mechanism):
- M1)抛出一个异常;
- M2)日志;
- M3)使用断言;
3.2)什么时候应该选择使用断言呢?记住下面几点(Points):
- P1)断言失败是致命的, 不可恢复的;
- P2)断言的检查只用于开发和测试阶段;
所以, 不应该使用断言向程序的其他部分通告发生了可恢复性的错误, 或者, 不应该作为程序向用户通告问题的手段。 断言只应该用于在测试阶段确定程序内部的错误位置;
3.3)看个荔枝:
- 3.3.1)文档指出, 如果方法中使用了错误的下标值,那么就会抛出一个异常, 这是方法与调用间约定的处理行为;
- 3.3.2)如果对这个方法做个改动:
@param a the array to be sorted (must not be null)
现在, 这个方法的调用者就必须注意了: 不允许用null 数组调用这个方法, 并在这个方法的开头使用断言: assert a!=null; - 3.3.3)前置条件:计算机科学家把这种约定称为前置条件;最初的方法对参数没有前置条件, 即承诺在任何条件下都能够给予正确的执行;修订后的方法有一个前置条件, 即 a 非空;
- 3.3.4)如果调用者在调用这个方法时没有提供满足这个前置条件的参数, 所有的断言都会失败, 并且这个方法可以执行它想做的任何操作;
【4】为文档假设使用断言
Conclusion)断言和日志记录的区别: 断言是一种测试和调试阶段所使用的战术性工具, 而日志记录是一种在程序的整个生命周期都可以使用的策略性工具;
- API java.lang.ClassLoader 1.0
void setDefaultAssertionStatus(boolean b) 1.4 : 对于通过类加载器的所有类来说, 如果没有显式地说明类或包的断言状态, 就启用或者禁用断言;
void setClassAssertionStatus(string className, boolean b) 1.4 :对于给定类和它的内部类, 启用或者禁用断言;
void setPackageAssertionStatus(string packageName, boolean b) 1.4 :对于给定包或其子包中的所有类, 启用或禁用断言;
void clearAssertionStatus() 1.4 :移除所有类和包的显式断言状态设置, 并禁用所有通过这个类加载器加载的类的断言;