2009-11-25 56 views
101

我的问题可能是非常基本的,但我认为它值得去问。我有以下代码:&&(AND)and || (或)在IF陈述

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) 

将Java的检查b如果a是在第一种情况下假,如果a在第二种情况下是真的吗?

回答

158

不,它不会被评估。这非常有用。就像你需要测试,如果一个字符串不为空或为空,你可以写:

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

,或者倒过来

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

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

+0

是否存在按位比较以便您可以评估这两个表达式?即如果(str!= null | str.isEmpty())? (当然这不是一个实际的例子,实际上它很愚蠢,但你明白了) – Kezzer

+5

只要表达式没有副作用,短路语义在逻辑上就等同于完整的评估。也就是说,如果A是真的,你知道A || B是真的,而不必评估B.只有当表达式有副作用时,才会有所作为。至于其他操作符,您可以使用'*'和'+'作为逻辑'和'和'或'; ((A1→0)×(B1→0))== 1“,((A1→0)+(B1→0))> 0。你甚至可以做'xor':'((A?1:0)+(B?1:0))== 1'。 – outis

+1

@Kezzer:是真的按位比较吗?我认为它是一个布尔逻辑运算符。它与'按位'(整数)运算符不同,尽管它们具有相同的符号... –

27

不,它不会被检查。这种行为被称为short-circuit evaluation,并且是许多语言(包括Java)的一项功能。

+2

@Azimuth:非常欢迎。如果你不知道什么,解决问题的最好方法就是问。 –

5

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

做一个简单的测试:

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

抛出NullPointerException

4

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

18

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

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

的& &操作就像&(§15.22.2),但评估其右边的操作数只有在其左侧操作数的值是true。 [...]在运行时,如果结果值为假,则条件表达式和表达式的值为假,并且右边的操作数表达式不被评估。如果左侧操作数的值为真,则右侧表达式将被求值,结果值将成为条件表达式和表达式的值。因此,& &计算与布尔操作数上的&相同的结果。它的区别仅在于右边的操作数表达式是有条件地而不是总是被评估的。

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

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

有点重复,也许,但他们确切地如何工作的最好证实。 ?

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

没有一个NullPointerException:同样条件运算符(:)仅如果值是如果这是真的假的,右半部分),允许像使用表达式计算相应的“半壁江山”(左半部分。

4

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

一个有趣的事实是,Java还使用了&|逻辑操作数(它们是超载,具有int类型,他们都期望位运算),以评估在表达,当你需要它也是有用的所有条款副作用。

+0

这很有意思,例如:给定一个返回布尔值的方法changeData(data),则: if(a.changeData(data)|| b.changeData(data)){doSomething(); } 不b上执行changeData如果a.changeData()返回true,但 如果(a.changeData(数据)| b.changeData(数据)){DoSomething的()} 执行changeData()上无论是a还是b,即使在返回的true上调用。 – Sampisa

51

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

&和& &是 “和” 的运营商,|和|| “或”操作符,^是“xor”

在检查参数值之前,单个参数将检查每个参数,而不考虑值。 双击将会首先检查左边的参数及其值,如果true||)或false&&)会保持第二个参数不变。 声音完整?一个简单的例子应该清楚:

鉴于所有的例子:

String aString = null; 

AND:

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无法优化,因为它取决于两个参数。

+2

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

+0

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

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); 
} 
4

此处的短路表示不会评估第二个条件。

如果(A & & B)将导致短路,如果A是假的。

如果(A & & B)将而不是导致短路如果A为真。

如果(A || B)将导致短路,如果A为真。

如果(A || B)将而不是如果A为False导致短路。