&&(AND)和|| (OR)在IF语句中


137

我有以下代码:

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

partialHitsHashMap 在哪里。
如果第一个陈述为真会怎样? Java还会检查第二条语句吗?因为为了使第一条语句为真,所以HashMap不应包含给定的键,因此如果选中了第二条语句,我将得到NullPointerException
简单来说,如果我们有以下代码

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

Java将在第一种情况下检查b是否a为false,a在第二种情况下是否为true?

Answers:


202

不,不会被评估。这非常有用。例如,如果您需要测试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())吗?(当然,这不是一个实际的例子,实际上是愚蠢的,但是您明白了)
Kezzer

5
只要这些表达式没有副作用,短路语义在逻辑上就等同于完整评估。也就是说,如果A为true,则无需评估B就知道A || B为true。唯一可以改变的时间是表达式是否具有副作用。至于其他运算符,您可以使用*+作为逻辑andor((A?1:0) * (B?1:0)) == 1((A?1:0) + (B?1:0)) > 0。你甚至可以做xor((A?1:0) + (B?1:0)) == 1
outis

1
@Kezzer:真的是按位比较吗?我认为这是boolean(逻辑)运算符。bitwise尽管具有相同的符号,但它与(整数)运算符不同……
user85421

4
要在“ &&”和“ ||”之间切换的便捷技巧 表达式将否定整个表达式,使得: !(str != null && !str.isEmpty()) 成为: (str !(!=) null !(&&) !(!)str.isEmpty()) 然后: (str == null || str.isEmpty()) 因为: !(!=) is == !(&&) is || !(!) eliminates itself 其他有用的否定是: !(<) is >= !(>) is <= 反之亦然
egallardo 2013年

68

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

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

单个值将在检查参数值之前检查每个参数,而与值无关。双重参数将首先检查左参数及其值,并且true||)或false&&)是否使第二个参数保持不变。声音编译好了吗?一个简单的例子应该很清楚:

给出所有示例:

 String aString = null;

和:

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

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

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

第一个参数被检查并返回false,因此第二个参数将不被检查,因为false无论如何结果都是如此。

或:

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

也将引发NullPointerException。

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

第一个参数被检查并返回true,因此第二个参数将不被检查,因为true无论如何结果都是如此。

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


3
“ Java有4个不同的布尔比较运算符:&,&&,| |,||” ...您忘记了^(xor)。
aioobe 2010年

哦,我还不知道它也会检查布尔值。到目前为止,仅用于位掩码。
硬编码


20

这里的所有答案都是不错的,但是只是为了说明问题的根源,对于此类问题,可以参考Java语言规范。

第15:23节“条件与运算符(&&) ”表示:

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

同样,第15:24节“条件或运算符(||) ”表示:

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

也许有些重复,但是最好地确认它们是如何工作的。类似地,条件运算符(?:)仅计算适当的“一半”(如果值为true,则为左半部分;如果为false,则为右半部分),从而允许使用以下表达式:

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

没有NullPointerException。


6

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

做一个简单的测试:

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

不会NullPointerException


6

此处的短路意味着将不评估第二个条件。

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

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

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

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


4

不,它不会,一旦知道结果,Java就会短路并停止评估。


4

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

一个有趣的事实是Java还使用&|作为逻辑操作数(它们是重载的,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时调用了该方法。
桑皮萨'17

0

这可以追溯到&和&&之间的基本区别。和||

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

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);   
} 
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.