【问题标题】:&& (AND) and || (OR) in IF statements&& (AND) 和 || (OR) 在 IF 语句中
【发布时间】:2010-12-20 05:30:29
【问题描述】:

我有以下代码:

if(!partialHits.get(req_nr).containsKey(z) || partialHits.get(req_nr).get(z) < tmpmap.get(z)){  
    partialHits.get(z).put(z, tmpmap.get(z));  
}

partialHits 是一个 HashMap。
如果第一个语句为真会发生什么? Java 还会检查第二个语句吗? 因为要使第一个语句为真,HashMap 不应该包含给定的键,所以如果第二条语句被选中,我会得到NullPointerException
所以简单来说,如果我们有以下代码

if(a && b)  
if(a || b)

如果a 在第一种情况下为假,而在第二种情况下a 为真,Java 是否会检查b

【问题讨论】:

    标签: java if-statement


    【解决方案1】:

    不,它不会被检查。这种行为称为short-circuit evaluation,是包括 Java 在内的许多语言的一个特性。

    【讨论】:

      【解决方案2】:

      不,如果 a 为真(在 or 测试中),则不会测试 b,因为无论 b 表达式的值是什么,测试的结果都将始终为真。

      做一个简单的测试:

      if (true || ((String) null).equals("foobar")) {
          ...
      }
      

      不会不会抛出NullPointerException

      【讨论】:

        【解决方案3】:

        不会,Java 会在知道结果后短路并停止评估。

        【讨论】:

          【解决方案4】:

          不,它不会被评估。这非常有用。例如,如果你需要测试一个String是否不为null或为空,你可以这样写:

          if (str != null && !str.isEmpty()) {
            doSomethingWith(str.charAt(0));
          }
          

          或者,反过来

          if (str == null || str.isEmpty()) {
            complainAboutUnusableString();
          } else {
            doSomethingWith(str.charAt(0));
          }
          

          如果我们在 Java 中没有“短路”,我们会在上面的代码行中收到很多 NullPointerExceptions。

          【讨论】:

          • 是否存在按位比较,以便您可以评估这两个表达式?即 if(str != null | str.isEmpty()) ? (当然这不是一个实际的例子,实际上它很愚蠢,但你明白了)
          • 只要表达式没有副作用,短路语义在逻辑上等价于完整的求值。也就是说,如果 A 为真,您无需评估 B 就知道 A||B 为真。唯一会产生影响的情况是表达式是否有副作用。至于其他运算符,您可以使用*+ 作为逻辑andor((A?1:0) * (B?1:0)) == 1((A?1:0) + (B?1:0)) &gt; 0。你甚至可以做xor:((A?1:0) + (B?1:0)) == 1
          • @Kezzer:这真的是按位比较吗?我认为这是一个boolean(逻辑)运算符。它与bitwise(整数)运算符不同,尽管符号相同...
          • 当你想在 '&&' 和 '||' 之间切换时的一个小技巧表达式是否定整个表达式,这样:!(str != null &amp;&amp; !str.isEmpty()) 变为:(str !(!=) null !(&amp;&amp;) !(!)str.isEmpty()) 然后:(str == null || str.isEmpty()) 因为:!(!=) is ==!(&amp;&amp;) is ||!(!) eliminates itself 其他有用的否定是:!(&lt;) is &gt;=!(&gt;) is &lt;= 和反之亦然
          【解决方案5】:

          这里的所有答案都很好,但为了说明这些问题的来源,对于此类问题,最好转到源代码:Java 语言规范。

          Section 15:23, Conditional-And operator (&&),说:

          && 运算符类似于 &(第 15.22.2 节),但仅当其左侧操作数的值为真时才计算其右侧操作数。 [...] 在运行时,首先计算左侧操作数表达式 [...] 如果结果值为 false,则条件与表达式的值为 false 并且不计算右侧操作数表达式.如果左侧操作数的值为真,则计算右侧表达式 [...] 结果值成为条件与表达式的值。因此, && 在布尔操作数上计算与 & 相同的结果。它的不同之处仅在于右手操作数表达式是有条件地计算而不是总是计算。

          同样,Section 15:24, Conditional-Or operator (||) 说:

          ||运算符就像 | (§15.22.2),但仅当其左侧操作数的值为假时才评估其右侧操作数。 [...] 在运行时,首先计算左侧操作数表达式; [...] 如果结果值为真,则条件或表达式的值为真,并且不计算右侧操作数表达式。如果左侧操作数的值为 false,则计算右侧表达式; [...] 结果值成为条件或表达式的值。因此,||计算与 | 相同的结果在布尔或布尔操作数上。它的不同之处仅在于右手操作数表达式是有条件地计算而不是总是计算。

          可能有点重复,但最好确认它们是如何工作的。同样,条件运算符 (?:) 只计算适当的“一半”(如果值为真,则左半边,如果为假,则右半边),允许使用如下表达式:

          int x = (y == null) ? 0 : y.getFoo();
          

          没有 NullPointerException。

          【讨论】:

            【解决方案6】:

            是的,布尔表达式的短路求值是所有类 C 系列的默认行为。

            一个有趣的事实是,Java 还使用 &amp;| 作为逻辑操作数(它们被重载,int 类型它们是预期的按位运算)来计算表达式中的所有项,即当您需要副作用时也很有用。

            【讨论】:

            • 这很有趣:例如给定一个返回布尔值的方法 changeData(data),然后: if (a.changeData(data) || b.changeData(data)) { doSomething();如果 a.changeData() 返回 true,则不会在 b 上执行 changeData,但如果 (a.changeData(data) | b.changeData(data)) { doSomething() } 在 a 和 b 上执行 changeData(),甚至如果在返回的 true 上调用。
            【解决方案7】:

            Java 有 5 种不同的布尔比较运算符:&、&&、|、||、^

            & 和 && 是“和”运算符,|和 || “或”运算符,^ 是“异或”

            在检查参数值之前,单个参数将检查每个参数,无论其值如何。 双重的将首先检查左边的参数及其值,如果 true (||) 或 false (&amp;&amp;) 保持第二个不变。 听起来很复杂?一个简单的例子应该清楚:

            给出所有示例:

             String aString = null;
            

            与:

             if (aString != null & aString.equals("lala"))
            

            在完成评估之前检查两个参数,并且将为第二个参数抛出 NullPointerException。

             if (aString != null && aString.equals("lala"))
            

            第一个参数被检查,它返回false,所以第二个参数不会被检查,因为结果是false

            OR 也一样:

             if (aString == null | !aString.equals("lala"))
            

            也会引发 NullPointerException。

             if (aString == null || !aString.equals("lala"))
            

            第一个参数被检查,它返回true,所以第二个参数不会被检查,因为结果是true

            XOR 无法优化,因为它取决于两个参数。

            【讨论】:

            • "Java 有 4 种不同的布尔比较运算符:&、&&、|、||"...您忘记了 ^ (xor)。
            • 哦,我不知道它也会检查布尔值。到目前为止,它只用于位掩码。
            【解决方案8】:

            这又回到了 & 和 && 之间的基本区别,|和 ||

            顺便说一句,您多次执行相同的任务。不确定效率是否是一个问题。您可以删除一些重复项。

            Z z2 = partialHits.get(req_nr).get(z); // assuming a value cannout be null.
            Z z3 = tmpmap.get(z); // assuming z3 cannot be null.
            if(z2 == null || z2 < z3){   
                partialHits.get(z).put(z, z3);   
            } 
            

            【讨论】:

              【解决方案9】:

              这里的短路意味着不会评估第二个条件。

              If ( A && B ) 如果 A 为 False 将导致短路。

              如果 ( A && B ) 如果 A 为真,则不会导致短路。

              If ( A || B ) 如果 A 为 True 则会导致短路。

              如果 ( A || B ) 如果 A 为 False,不会导致短路。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2017-03-21
                • 1970-01-01
                • 1970-01-01
                • 2012-02-22
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多