什么时候用assert
考点:考察求职者对Java断言的理解。
出现频率:★★★★
【面试题解析】
assert是在J2SE 1.4中引入的新特性,assertion是在代码中包含的一种布尔型状态,程序员认为这个状态是true。一般来说,assert在开发的时候是检查程序的安全性的,在发布的时候通常都不使用assert。
首先,有必要从一个例子说起,示例代码如下:
public class AssertTest { public static void main(String[] args) { AssertTest at = new AssertTest(); at.assertMe(true); at.assertMe(false); } private void assertMe(boolean boo) { assert boo?true:false; System.out.println("true condition"); } }
程序中包含了assert的话,要用“javac -source 1.4 xxx.java”来编译,否则编译器会报错。要想让assert的部分运行的话,要使用“java -ea xxx”来运行,否则包含assert的行会被忽略。在命令行输入如下命令:
javac -source 1.4 AssertTest.java java -ea AssertTest
输出结果如下:
true condition Exception in thread "main" java.lang.AssertionError at AssertTest.assertMe(AssertTest.java:13) at AssertTest.main(AssertTest.java:7)
当运行at.assertMe(true)的时候,由于“assert boo?true:false”相当于“assert true;”,因此没有任何问题,程序往下执行,打印出“true condition”,但是执行at.assertMe(false)的时候相当于“assert false”,这个时候解释器就会抛出AssertionError,程序就终止了。AssertionError是继承自Error的,可以在程序中捕获它,然后程序可以继续执行。示例代码如下:
public class AssertTest { public static void main(String[] args) { AssertTest at = new AssertTest(); try { at.assertMe(true); at.assertMe(false); } catch(AssertionError ae) { System.out.println("AsseriontError catched"); } System.out.println("go on"); } private void assertMe(boolean boo) { assert boo?true:false; System.out.println("true condition"); } }
assert还有另外一种表达的方式,就是“assert eXP1:exp2;“,其中exp1是个boolean返回值的表达式,而exp2是原始的数据类型或者对象都可以。示例代码如下:
boolean boo = true; String str = null; assert boo = false:str="error";
刚开始讲的assert exp1的形式,当exp1是false的时候,AssertionError的默认构造器会被调用。但是对“assert exp1:exp2”这样的形式,当exp1为true的时候,后面的exp2被忽略,如果false的话,后面的表达式的结果会被计算出来,并作为AssertionError的构造器参数。示例如下:
public class AssertTest { public static void main(String[] args) { AssertTest at = new AssertTest(); at.assertMe(true); at.assertMe(false); } private void assertMe(boolean boo) { String s = null; assert boo?true:false:s = "hello world"; System.out.println("true condition"); } }
运行结果如下:
true condition Exception in thread "main" java.lang.AssertionError: hello world at AssertTest.assertMe(AssertTest.java:14) at AssertTest.main(AssertTest.java:7)
Assert最好不要滥用,原因是assert并不一定都是enable的,下面两种情况就不应该用assert。
不要在public的方法里面检查参数是不是为null之类的操作,示例代码如下:
public int get(String s) { assert s != null; }
如果需要检查,也最好通过“if s = null”抛出NullPointerException来检查,不要用assert来检查方法操作的返回值来判断方法操作的结果。
例如“assert list.removeAll();”这样看起来好像没有问题,但是如果assert被disable,语句就不会被执行了,所以removeAll()操作就没有被执行,可以这样代替:
boolean boo = list.removeAl(); assert boo;
注意:assert是SCJP1.4的考试内容,所以还是非常有必要熟悉和掌握的。
参考答案:
断言是一个包含布尔表达式的语句,在执行这个语句时,假定该表达式为true。如果表达式计算为false,那么系统会报告一个Assertionerror。它用于调试目的:
assert(a > 0); // throws an Assertionerror if a <= 0
断言可以有两种形式:
assert Expression1 ; assert Expression1 : Expression2 ;
• Expression1应该总是产生一个布尔值。
• Expression2可以是得出一个值的任意表达式。这个值用于生成显示更多调试信息的String消息。
断言在默认情况下是禁用的。要在编译时启用断言,需要使用source 1.4标记:
javac -source 1.4 Test.java
要在运行时启用断言,可使用-enableassertions或者-ea标记。
要在运行时选择禁用断言,可使用-da或者-disableassertions标记。
要在系统类中启用断言,可使用-esa或者-dsa标记,还可以在包的基础上启用或者禁用断言。
可以在预计正常情况下不会到达的任何位置上放置断言。断言可以用于验证传递给私有方法的参数。不过,断言不应该用于验证传递给公有方法的参数,因为不管是否启用了断言,公有方法都必须检查其参数。
不过,既可以在公有方法中,也可以在非公有方法中利用断言测试后置条件。另外,断言不应该以任何方式改变程序的状态。