【问题标题】:Java operator precendece confusion && and ++Java 运算符优先级混淆 && 和 ++
【发布时间】:2013-12-28 10:58:46
【问题描述】:

&& 是一个短路运算符,从左到右求值,所以如果&& 运算符左侧的操作数被求值为假,求值应该继续。但我希望++ 应该在&& 之前评估,因为它有higher precedence,并且(来自链接):

优先级较高的运算符在优先级较低的运算符之前进行评估。

那么,为什么count 不在这段代码的第三行增加呢?

int mask = 2;
int count = 0;
if( !(mask > 1) && ++count > 1) { mask += 100; }
System.out.println(mask + " " + count);

【问题讨论】:

  • 有问题的句子可以修改为“具有较高优先级的运算符在具有较低优先级的运算符之前被评估如果它们被评估”。对于大多数运算符,计算顺序是“计算左操作数,计算右操作数,计算运算符”,但短路运算符是该规则的例外,因为它们可能导致其中一个操作数不被计算。
  • 我关于 C# 中运算符优先级的系列文章可能会对您有所帮助。它们也适用于 Java。 ericlippert.com/tag/precedence

标签: java operators operator-precedence


【解决方案1】:

不,表达式的计算方式是从左到右,同时考虑运算符的优先级。因此,一旦在 a && b 中,a 变为 false,b 将不再被评估。

JLS §15.23. Conditional-And Operator && 说:

条件与运算符&& 类似于&(第15.22.2 节),但仅当其左侧操作数的值为真时才计算其右侧操作数。


以下是对其工作原理的详细分步评估:

这是因为,当您将表达式解析为人类时,您首先从最低优先级运算符开始。在这种情况下,&& 的优先级低于 ++

++a < 0 && foo
        ^^
       start

为了计算&amp;&amp;的结果,你应该知道左操作数:

++a < 0 && ++b
^^^^^^^
so compute this

现在,当你想知道++a &lt; 0 的结果时,先看看最低优先级运算符,即&lt;

++a < 0
    ^
   evaluate this

为此,您需要左右操作数。所以计算它们:

++a
0

这是++a 增加的时刻。

所以,现在我们处于底部。让我们回到顶部:

false && foo

这就是 && 短路的事实。左操作数为假,因此右操作数表达式 foo 不再计算。变成:

false

不计算正确的操作数。

【讨论】:

    【解决方案2】:

    编辑:我错过了问题的重点。有关短路评估的半详细说明,请参见修订版。

    逻辑与和逻辑或运算符的每个操作数都是一个单独的表达式,因此被独立处理(根据正确的运算符优先级给定其自身的运算符求值顺序)。

    因此,虽然 ++++count &gt; 1 中具有最高优先级,但该 表达式 甚至从未被评估(因为短路)。

    【讨论】:

    • @Peter 这里的关键是优先级!= 评估顺序
    • @user3125280 这对我很有帮助。除了逻辑 AND (&&) 和 OR (||) 运算符之外,还有两个具有“固定”评估顺序的运算符。有条件 (?:) 和逗号 (,) 运算符。
    【解决方案3】:

    您似乎对短路评估说明不满意。为什么优先级在这里不重要?

    想象一下这段代码:

    if( !(mask > 1) && Increment(count) > 1)
    

    函数应用(即写括号调用函数)是最高优先级,但函数调用永远不会发生。如果短路评估允许优先级,那它根本就不起作用。

    扩展一点 - 诸如 ++ 、 - 等运算符都映射到函数调用。但是,编译器需要了解它们绑定的顺序。这不是他们被评估的顺序。

    所以a + b * c 并不意味着锻炼 b * c 然后是总和。就是说只有这个add( a, multiply(b, c))在&&的情况下求值顺序不同(虽然在我的例子中没有),方便程序员编写快速代码。

    【讨论】:

      【解决方案4】:

      为避免混淆,请记住

      if (a && b) {
          // do something
      }
      

      在语义上与:

      if (a) {
          if (b) {
               // do something
          }
      }
      

      显然,如果 a 的计算结果为 false,则永远不会看到术语 b。特别是,那里的增量运算符不会执行。

      通过回忆这个扩展,行为应该更容易理解。最好将&amp;&amp; 视为上述嵌套if 语句的快捷方式。 (在有else 语句的情况下,您还需要添加两个else 代码副本,因此并不容易。)

      更“精确”的表示是使用条件方法:

      boolean condition() {
          if (!a) return false;
          if (!b) return false;
          return true;
      }
      

      同样,如果 a 已经返回 false,则永远不会评估 b

      【讨论】:

        【解决方案5】:

        if( !(mask > 1) && ++count > 1) { mask += 100; }

        这条线表示的是: !(2&gt;1)!(true)false

        &amp;&amp; 左侧为假,不再检查右侧

        所以count 不会增加。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-09-30
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-08-16
          • 2012-12-13
          相关资源
          最近更新 更多