【问题标题】:When Java evaluates a conjunction (<boolean exp1> && <boolean exp2>), does it eval exp2 if exp1 is false?当 Java 评估一个连词 (<boolean exp1> && <boolean exp2>) 时,如果 exp1 为假,它是否评估 exp2?
【发布时间】:2012-03-15 18:04:07
【问题描述】:

我想知道是否可以保证在 Java 程序中,只要左侧的表达式 (exp1) 评估为 false,就不会评估连接右侧的布尔表达式(上面的 exp2)。我想知道,因为我有如下表达式:

if (var != null && var.somePredicate())
   // do something

如果 Java 在看到 var 为 null 后不能保证停止评估 (var != null &amp;&amp; var.somePredicate()),那么它可能会尝试评估 var.somePredicate(),这将引发 NullPointerException。

所以我的问题是,Java 在这方面是否保证某种行为?还是写起来更安全

if (var != null)
{
   if (var.somePredicate())
      // do something
}

【问题讨论】:

    标签: java conditional boolean expression evaluation


    【解决方案1】:

    来自 Java 语言规范,15.23 Conditional-And Operator &&

    &amp;&amp; 运算符类似于 &amp;(第 15.22.2 节),但仅当其左侧操作数的值为真时才评估其右侧操作数

    因此语言规范保证如果左侧为假,则不会计算表达式的右侧。

    【讨论】:

      【解决方案2】:

      让我们通过直接查看从该示例代码生成的操作码来执行我们自己的实验:

      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,它将跳过第二个 @987654326 @ 指令直接指向 else 语句。

      这称为短路评估。

      【讨论】:

        【解决方案3】:

        如果你使用 && 或 ||,java 将使用短路评估(即除非需要,否则不会评估第二个表达式)

        如果使用 & 或 |,java 将始终计算第二个表达式,即使第一个表达式为真

        【讨论】:

          【解决方案4】:

          不,java 使用Short circuit evaluation。如果expr1false,则不会评估expr2,因此您的&amp;&amp; 使用是非常安全的。

          另外,如果您有if (exp1 || exp2) { .. } - 如果exp1true,则不会评估exp2

          【讨论】:

          • 这不是懒惰的评估,而是短路。我不相信 Java 本身支持惰性求值。
          • @Mat:根据维基百科:Short-circuit evaluation of Boolean control structures is sometimes called "lazy". 所以我们都是对的。 [虽然我相信短路术语确实更好 - 我会编辑,谢谢。]
          【解决方案5】:

          这很安全,Java 会进行短路评估。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-08-16
            • 1970-01-01
            • 2016-08-25
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多