【问题标题】:Java's logical OR operator does not evaluate right hand side despite that right hand side has a unary operator?尽管右手边有一个一元运算符,Java 的逻辑 OR 运算符不会评估右手边?
【发布时间】:2013-09-02 14:52:51
【问题描述】:

鉴于:

Object x = null;

考虑代码 sn-p #1:

if (x == null || !x.equals(new Object()))
    System.out.println("I print!");

代码 sn-p #1 并没有像我最初认为的那样抛出 NullPointerException。在| 操作员的一点帮助下,我可以引发异常。代码 sn-p #2:

if (x == null | !x.equals(new Object()))
    System.out.println("This will throw a NullPointerException..");

那么为什么我的第一个代码 sn-p 从未计算过其中包含一元 NOT 运算符的正确表达式(感叹号 !)?根据..所有网站..一元NOT运算符的优先级高于逻辑OR运算符(||)。

【问题讨论】:

  • 因为如果OR 中的第一个条件为真,那么评估第二个条件的意义何在?
  • 是的,我知道,问题是一元 NOT 运算符 (!) 具有更高的优先级,他应该在 OR 运算符之前进行评估。或者我是这么想的!

标签: java operator-precedence unary-operator logical-or


【解决方案1】:

一元 NOT 运算符的优先级高于逻辑 OR 运算符 (||)。

是的,这是真的。但是,如果在逻辑 OR 的第一个表达式上使用 NOT,优先级就会生效。

考虑条件:

if (!x.equals(y) || y.equals(z))

在这种情况下,否定将首先应用于x.equals(y) 的结果,然后是逻辑或。因此,如果|| 的优先级大于!,则表达式将被计算为:

if (!(x.equals(y) || y.equals(z)))

但事实并非如此。你知道为什么。

但是,如果 NOT 运算符在第二个表达式上,则此处的优先级不是一个点。第一个表达式总是在第二个表达式之前首先被计算。短路行为将发挥作用。

【讨论】:

  • 谢谢你的例子。正是这个例子,再加上彼得劳里的“优先级 = 隐含括号在哪里”,最终让我朝着正确的方向前进。任何其他与我有相同问题的人都应该考虑这段代码:if (one() || two() && three())&& 运算符的优先级也高于 || 运算符。但是 if 子句是这样评估的:if (one() || (two() && three())).
【解决方案2】:

优先级 == 评估顺序是一个常见的误解。这并非总是如此。优先级决定了编译器构建表达式的顺序,这可以导致生成的代码匹配该顺序,但在某些情况下,例如这不适用的 post increment 和 short curcuit 运算符。

所有优先级意味着隐含括号的位置,例如

if (x == null || !x.equals(new Object()))

相同
if ((x == null) || (!(x.equals(new Object()))))

【讨论】:

  • +1。 “所有优先级意味着隐含括号的位置”
  • 是的,优先级真的很有帮助。对我来说,是 Rohit Jain 的例子让我思考得直,所以我不得不将他的答案标记为接受的答案。彼得,您关于“优先级 = 隐含括号在哪里”的注释确实很有帮助。请参阅我对 Rohit 的评论,了解我在您的帮助下设法构建的示例。
【解决方案3】:

这在this Java tutorial 中有解释。如果第一个布尔表达式分别导致truefalse,则||&& 会短路执行。

一元 ! 的优先级高于按位 OR |。优先规则见here

【讨论】:

  • 我知道短路,但一元NOT的优先级高于逻辑OR运算符?
  • @Martin 是的,确实如此。见这里:docs.oracle.com/javase/tutorial/java/nutsandbolts/…
  • @MartinAndersson 优先级和评估顺序是不同的问题。将优先级视为告诉您将括号放在哪里以获得与原始表达式等效的全括号表达式。为每个运算符指定评估顺序。
【解决方案4】:

阅读short-circuit evaluation - 在逻辑 OR 语句 (||) 中,仅当第一个参数为假时才计算第二个参数。

使用第二个运算符(bitwise inclusive or|),两个参数都被计算(它不会短路)。因此,因为x 为空,第二个会抛出NullPointerException 而第一个不会。

【讨论】:

    【解决方案5】:

    如果 Java 在这方面类似于 C#,那么像 ||&& 这样的逻辑运算符是从左到右计算的。如果p == true 然后p OR q == true,根据定义,所以评估OR 的右手是没有意义的。

    这让你不必做这样的事情(当然,比评估大量冗余表达式更有效):

    if (x != null)
    {
        if (x.Property > 0)
        {
            ....
        }
    }
    

    我不确定这里的优先级有多相关,因为 NOT 排除了提供的条件中的第一个表达式,所以右手的值无论如何都与左手的值无关。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-06-02
      • 2016-04-14
      • 2020-07-22
      • 1970-01-01
      • 1970-01-01
      • 2021-10-03
      • 1970-01-01
      • 2014-12-15
      相关资源
      最近更新 更多