当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使用短路评估 。 如果expr1false ,则不会计算expr2 ,因此您的&&使用是完全安全的。

此外,如果你有if (exp1 || exp2) { .. } – 如果exp1true则不会评估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会进行短路评估。