【问题标题】:What is wrong with the short circuit logic in this Java code?这个 Java 代码中的短路逻辑有什么问题?
【发布时间】:2010-10-25 13:29:11
【问题描述】:

为什么 func3 在下面的程序中没有被执行?在func1之后,func2不需要被评估但是对于func3,不是吗?

if (func1() || func2() && func3()) {
        System.out.println("true");
    } else {
        System.out.println("false");
    }
}

public static boolean func1() {
    System.out.println("func1");
    return true;
}

public static boolean func2() {
    System.out.println("func2");
    return false;
}

public static boolean func3() {
    System.out.println("func3");
    return false;
}

【问题讨论】:

  • 这提出了一点,在任何类型的非平凡表达中,用括号声明你的意图是个好主意。因此,即使您打算 (func1() || (func2() && func3()),您也要让后来出现的程序员清楚明白地表明您的代码正在按预期工作。

标签: java logical-operators


【解决方案1】:

如果您希望执行所有功能,您可以删除快捷方式

if (func1() | func2() & func3()) {

【讨论】:

    【解决方案2】:

    您使用的是短路或。如果第一个参数为真,则整个表达式为真。

    如果我添加编译器使用的隐式括号可能会有所帮助

    编辑:正如 Chris Jester-Young 所说,这实际上是因为逻辑运算符必须具有从左到右的关联性:

    if (func1() || (func2() && func3()))
    

    func1返回后变成这样:

    if (true || (func2() && func3()))
    

    评估短路或后,变为:

    if (true)
    

    【讨论】:

    • 为免生疑问,这是因为 && 的优先级高于 ||。在这两种情况下,关联性都是从左到右的。
    • 我之所以提到这一点,是因为否则这篇文章会导致一个问题,为什么是 (A || (B && C)) 而不是 ((A || B) && C)。
    • (对于晚上来说,重要的是优先级在这里很重要,没有关联性不会被看进去。IMO,诸如a || b && ca && b || c之类的表达式(即`(a && b) || c) 令人困惑,编译器应该抱怨。)
    【解决方案3】:

    根据precedence rules评估Java函数

    因为“&&”的优先级高于“||”,所以首先计算它,因为您没有任何括号来设置显式优先级

    所以你的表达方式

    (A || B && C) 
    

    这是

    (T || F && F)
    

    被括号括起来

    (T || (F && F)) 
    

    因为优先规则。

    由于编译器知道如果 'A == true' 它不需要计算表达式的其余部分,它会在计算 A 后停止。

    如果您将 ((A || B) && C) 括起来,那么它的计算结果为 false。

    编辑

    另一种方式,正如其他海报所提到的,使用“|”和“&”而不是“||”和“&&”,因为这会阻止表达式的快捷方式。 但是,由于优先规则,最终结果仍然是相同的。

    【讨论】:

      【解决方案4】:

      Java 使用惰性求值。

      由于 Func1 始终返回 true,因此整个表达式必须为 true,因此它会缩短表达式的其余部分。

      true || (???)
      

      false && (???)
      

      总是捷径。

      要关闭快捷方式评估,请使用 |和 & 而不是 ||和&&

      我们可以用这个来达到很好的效果:

      String s;
      if (s != null && !s.equals("")) ...
      

      意味着如果 s 为 null,我们甚至不必尝试调用 s.equals,也不会最终抛出 NullPointerException

      【讨论】:

      • 它并不总是捷径。它根据优先规则进行评估。我没有方便的 java 编译器,但我相信 (falsefunc() && true1() || true2()) 将评估 falsefunc() 然后 true2()。
      【解决方案5】:

      您正在使用快捷操作符 ||和 &&。如果结果已经定义,这些运算符不会执行表达式的其余部分。对于 ||这意味着如果第一个表达式为真,对于 && 如果第一个表达式为假。

      如果要执行表达式的所有部分,请使用 |而 & 相反,这不是捷径。

      【讨论】:

        【解决方案6】:

        如果函数 1 总是返回 true,那么 Java 不需要评估表达式的其余部分来确定整个表达式是否为 true。

        【讨论】:

          【解决方案7】:
          【解决方案8】:

          简短回答:short-circuit evaluation

          由于 func1() 为真,因此无需继续评估,因为它始终为真

          【讨论】:

            【解决方案9】:

            Java 使布尔表达式短路。这意味着,一旦执行func1() 并返回true,布尔值的其余部分就无关紧要了,因为您使用的是or 运算符。无论func2() && func3() 计算为什么,整个表达式都将计算为true。因此,Java 甚至不会费心评估 func2()func3()

            【讨论】:

              猜你喜欢
              • 2020-10-31
              • 2013-01-16
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2020-07-08
              相关资源
              最近更新 更多