当Java计算一个连词( && )时,如果exp1为false,它是否eval exp2?
我想知道是否保证在Java程序中,只要左边的表达式(exp1)评估为false,就不会计算连接右边的布尔表达式(上面的exp2)。 我想知道因为我有一个如下表达式:
if (var != null && var.somePredicate()) // do something
如果Java在看到var
为null之后不能保证停止评估(var != null && var.somePredicate())
,那么它可能会尝试评估会引发NullPointerException的var.somePredicate()
。
所以我的问题是,Java在这方面是否保证了某种行为? 或者写起来会更安全
if (var != null) { if (var.somePredicate()) // do something }
从Java语言规范, 15.23条件和运算符&& :
&&
运算符类似于&
(§15.22.2),但仅当其左侧操作数的值为true时才计算其右侧操作数 。
因此语言规范保证如果左侧是假的,则不会评估表达式的右侧。
不,java使用短路评估 。 如果expr1
为false
,则不会计算expr2
,因此您的&&
使用是完全安全的。
此外,如果你有if (exp1 || exp2) { .. }
– 如果exp1
为true
则不会评估exp2
。
让我们直接查看从此示例代码生成的操作码来执行我们自己的实验:
public class Compare { public static void main(String... args) { boolean t = true; boolean f = false; if(f && t) { System.out.println("Both true"); } else { System.out.println("One false"); } } }
javap -v
生成:
0: iconst_1 1: istore_1 2: iconst_0 3: istore_2 4: iload_2 5: ifeq 23 8: iload_1 9: ifeq 23 12: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream; 15: ldc #3; //String No 17: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V 20: goto 31 23: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream; 26: ldc #5; //String Yes 28: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V 31: return
相关的操作码是我的小程序的ifeq
。 他们检查变量是否等于0,并且如果它们是操作码23,则向前跳转一定数量的操作。因此,如果第一个ifeq
评估为false,它将直接跳过第二个ifeq
指令。 else语句。
这称为短路评估。
如果使用&&或||,java将使用短路评估(即除非需要,否则不评估第二个表达式)
如果使用&或|,则java将始终计算第二个表达式,即使第一个表达式为真
这是安全的,Java会进行短路评估。