安康免费做网站,南昌编程培训机构,网站 linux 服务器配置,域名服务商平台大部分转载自参考资料#xff1a;http://www.ibm.com/developerworks/cn/java/l-javaassertion/index.html assertion(断言)在软件开发中是一种常用的调试方式#xff0c;assertion就是在程序中的一条语句#xff0c;它对一个boolean表达式进行检查#xff0c;一个正确程序…大部分转载自参考资料http://www.ibm.com/developerworks/cn/java/l-javaassertion/index.html assertion(断言)在软件开发中是一种常用的调试方式assertion就是在程序中的一条语句它对一个boolean表达式进行检查一个正确程序必须保证这个boolean表达式的值为true如果该值为false说明程序已经处于不正确的状态下系统将给出警告或退出。一般来说assertion用于保证程序最基本、关键的正确性。assertion检查通常在开发和测试时开启。为了提高性能在软件发布后assertion检查通常是关闭的。下面简单介绍一下Java中assertion的实现。 1.1 语法表示 在语法上为了支持assertionJava增加了一个关键字assert。它包括两种表达式 1) assert expression1; 2) assert expression1: expression2; 表达式中expression1表示一个boolean表达式expression2表示一个基本类型或者是一个Object的instance基本类型包括boolean,char,double,float,int和long。由于所有类都为Object的子类因此这个参数可以用于所有class的instance。 1.2 语义含义 在运行时如果关闭了assertion功能这些语句将不起任何作用。如果打开了assertion功能那么expression1的值将被计算如果它的值为false该语句将抛出一个AssertionError对象。如果assertion语句包括expression2参数程序将计算出expression2的结果然后将这个结果作为AssertionError的构造函数的参数来创建AssertionError对象并抛出该对象如果expression1值为trueexpression2将不被计算。 一种特殊情况是如果在计算表达式时表达式本身抛出Exception那么assert将停止运行而抛出这个Exception。 1.3 举例 assert 0 value;assert 0 value:valuevalue;assert ref ! null:ref doesnt equal null;assert isBalanced();1.4 编译 必须使用JDK1.4(或者更新)的Java编译器 1.5 运行 我们可以选择开启assertion功能或者不开启另外我们还可以开启一部分类或包的assertion功能通过这些选项我们可以过滤所有我们不关心的类只选择我们关心的类或包来观察下面介绍部分选项 -esa和 -dsa 含义为开启(关闭)系统类的assertion功能。由于新版本的Java的系统类中也使了assertion语句因此如果用户需要观察它们的运行情况就需要打开系统类的assertion功能 我们可使用-esa参数打开使用 -dsa参数关闭。 -esa和-dsa的全名为-enablesystemassertions和-disenablesystemassertions全名和缩写名有同样的功能 -ea和 -ea 含义为开启(关闭)用户类的assertion功能通过这个参数用户可以打开某些类或包的assertion功能同样用户也可以关闭某些类和包的assertion功能。打开assertion功能参数为-ea如果不带任何参数表示打开所有用户类如果带有包名称或者类名称表示打开这些类或包如果包名称后面跟有三个点代表这个包及其子包如果只有三个点代表无名包。关闭assertion功能参数为-da使用方法与-ea类似。 -ea和-da的全名为-enableassertions和-disenableassertions全名和缩写名有同样的功能 下面表格表示了参数及其含义并有例子说明如何使用 其中...代表此包和其子包的含义。例如我们有两个包为pkg1和pkg1.subpkg。那么pkg1...就代表pkg1和pkg1.subpkg两个包。 另外Java为了让程序也能够动态开启和关闭某些类和包的assertion功能Java修该了Class和ClassLoader的实现增加了几个用于操作assert的API。下面简单说明一下几个API的作用。 ClassLoader类中的几个相关的API: setDefaultAssertionStatus:用于开启/关闭assertion功能 setPackageAssertionStatus:用于开启/关闭某些包的assertion功能 setClassAssertionStatus: 用于开启/关闭某些类的assertion功能 clearAssertionStatus用于关闭assertion功能 1.6 assertion的设计问题 首先我们认为assertion是必要的。因为如果没有统一的assertion机制Java程序通常使用if-then-else或者switch-case语句进行assertion检查而且检查的数据类型也不完全相同。assertion机制让Java程序员用统一的方式处理assertion问题而不是按自己的方式处理。另外如果用户使用自己的方式进行检查那么这些代码在发布以后仍然将起作用这可能会影响程序的性能。而从语言言层次支持assertion功能这将把assertion对性能带来的负面影响降到最小。 Java是通过增强一个关键字assert实现支持assertion而不是使用一个库函数支持这说明Java认为assertion对于语言本身来说是非常重要的。实际上在Java的早期的规范中Java是能够支持assert的但是由于一些实现的限制这些特性从规范中除去了。因此assert的再次引入应该是恢复了Java对assert的支持。C语言就是通过Assert.h函数库实现断言的支持。 Java的assertion的开启也和C语言不太一样我们都知道在C语言中assertion的开启是在编译时候决定的。当我们使用debug方式编译程序时候assertion被开启而使用release方式编译时候assertion自动被关闭。而Java的assertion却是在运行的时候进行决定的。其实这两种方式是各有优缺点。如果采用编译时决定方式开发人员将处理两种类型的目标码debug版本和release版本这加大了文档管理的难度但是提高了代码的运行效率。Java采用运行时决定的方式这样所有的assertion信息将置于目标代码中同一目标代码可以选择不同方式运行增强目标代码的灵活性但是它将牺牲因为assertion而引起一部分性能损失。Java专家小组认为所牺牲的性能相当小因此java采用了运行时决定方式。 另外我们注意到AssertionError作为Error的一个子类而不是RuntimeException。关于这一点专家组也进行了长期的讨论。Error代表一些异常的错误通常是不可以恢复的而RuntimeException强调该错误在运行时才发生的特点。AssertionError通常为非常关键的错误这些错误往往是不容易恢复的而且assertion机制也不鼓励程序员对这种错误进行恢复。因此为了强调assertion的含义Java专家小组选择了让AssertError为Error的子类。 1.7 assertion与继承 考虑assertion与继承的关系研究assert是如何定位的。如果开启一个子类的assertion那么它的父类的assertion是否执行 下面的例子将显示如果一个assert语句在父类而当它的子类调用它时该assert为false。我们看看在不同的情况下该assertion是否被处理。 1 class Base {2 public void baseMethod() {3 assert false : Assertion failed:This is base ;// 总是assertion失败4 System.out.println(Base Method);5 }6 }7 class Derived extends Base {8 public void derivedMethod() {9 assert false: Assertion failed:This is derive;// 总是assertion失败
10 System.out.println( Derived Method );
11 }
12 public static void main( String[] args ) {
13 try {
14 Derived derived new Derived();
15 derived.baseMethod( );
16 derived.derivedMethod();
17 }
18 catch( AssertionError ae ) {
19 System.out.println(ae);
20 }
21 }
22 } 从这个例子我们可以看出父类的assert语句将只有在父类的assert开启才起作用如果仅仅开启子类的assert父类的assert仍然不运行。例如我们执行java -ea:Derived Derived的时候Base类的assert语句并不执行。因此我们可以认为assert语句不具有继承功能。 1.8 assertion的使用 assertion的使用是一个复杂的问题因为这将涉及到程序的风格assertion运用的目标程序的性质等问题。通常来说assertion用于检查一些关键的值并且这些值对整个程序或者局部功能的完成有很大的影响并且这种错误不容易恢复的。assertion表达式应该短小、易懂如果需要评估复杂的表达式应该使用函数计算。以下是一些使用assertion的情况的例子这些方式可以让java程序的可靠性更高。 1) 检查控制流在if-then-else和swith-case语句中我们可以在不应该发生的控制支流上加上assert false语句。如果这种情况发生了assert能够检查出来。 例如x取值只能使1,2,3我们的程序可以如下表示 1 switch (x) {
2 case 1: …;
3 case 2: …;
4 case 3: …;
5 default: assert false:x value is invalid: x;
6 } 2) 在私有函数计算前检查输入参数是否有效对于一私有些函数要求输入满足一些特定的条件那么我们可以在函数开始处使用assert进行参数检查。对于公共函数我们通常不使用assertion检查因为一般来说公共函数必须对无效的参数进行检查和处理。而私有函数往往是直接使用的。 例如某函数可能要求输入的参数必须不为null。那么我们可以在函数的一开始加上 assert parameter1!null : paramerter is null in test method; 3) 在函数计算后检查函数结果是否有效对于一些计算函数函数运行完成后某些值需要保证一定的性质因此我们可以通过assert检查该值。 例如我们有一个计算绝对值的函数那么我们就可以在函数的结果处加上一个语句 assert value 0 : Value should be bigger than 0: value; 通过这种方式我们可以对函数计算完的结果进行检查。 4) 检查程序不变量有些程序中存在一些不变量在程序的运行生命周期这些不变量的值都是不变的。这些不变量可能是一个简单表达式也可能是一个复杂的表达式。对于一些关键的不变量我们可以通过assert进行检查。 例如在一个财会系统中公司的支出和收入必须保持一定的平衡关系因此我们可以编写一个表达式检查这种平衡关系如下表示 private boolean isBalance() {// ...
} 在这个系统中在一些可能影响这种平衡关系的方法的前后我们都可以加上assert验证 assert isBalance():balance is destoried; 下面是搜集的一个网友对assertion的看法摘录此处作为参考 assert 有很大的用处首先可以用在单元测试代码中。junit侵入性是很强的如果整个工程大量的代码都使用了junit就难以去掉或者是选择另外一个框架。如果单元测试代码很多并且想复用这些单元测试案例应该选择assert而不是junit便于使用别的单元测试框架比如TestNG。同理正式的功能代码根本就不应该出现Junit应该使用assert.assert主要适合在基类框架类接口类核心代码类工具类中。换言之当你的代码的调用者是另外一个程序员写得业务代码或者是另外一个子系统时就很有必要使用它。比如你做了一个快速排序的算法public static Listint quickSort(Listint list){ assert list ! null; // 申请临时空间 //开始排序 for(int i : list){ // }}这种情况下如果不检查传入参数的正确性会抛出一个莫名其妙的空指针错误。你的调用者可能并不清楚你代码的细节在一个系统的深处调试一个空指针错误是很浪费时间的。就应该直接明确的告诉你的调用者是传入的参数有问题。否则他会怀疑你的代码有BUG。使用assert可以避免两个程序员之间互相指责对方写的代码有问题。assert适用那些你知道具体是什么错误你和你的调用者已经约定应该由你的调用者去排除或检查的错误。你通过一个断言告诉你的调用者。assert不适用那些外部系统造成的错误比如用户输入数据的错误某个外部文件格式错误。这些错误不是你的调用者而是用户造成的甚至于不属于异常因为出现输入错误和文件格式错误是经常的这些错误应该由业务代码去检查。assert比较适合于被频繁调用的 基类框架代码工具类核心代码接口代码中这正是它在运行时被去掉的原因。测试代码应该在测试阶段开启-ea参数便于对系统深处的核心代码做仔细的测试。Java较少使用assert的原因是Java有很完整的OO体系强制类型转换出现得较少所以不需要类似c那样需要频繁的检查指针的类型是否正确指针是否为空。同时Java也很少直接管理内存或缓冲区所以不需要频繁的检查传入的缓冲区是否为空或者是已经越界。但使用好assert有助于提高框架代码的正确性和减少框架代码的使用者的调试时间。转载于:https://www.cnblogs.com/qrlozte/archive/2013/03/20/2971361.html