&& (AND) and || (OR) in IF statements

2019-01-01 12:49发布

问题:

I have the following code:

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

where partialHits is a HashMap.
What will happen if the first statement is true? Will Java still check the second statement? Because in order the first statement to be true, the HashMap should not contain the given key, so if the second statement is checked, I will get NullPointerException.
So in simple words, if we have the following code

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

would Java check b if a is false in the first case and if a is true in the second case?

回答1:

No, it will not be evaluated. And this is very useful. For example, if you need to test whether a String is not null or empty, you can write:

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

or, the other way around

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

If we didn\'t have \'short-circuits\' in Java, we\'d receive a lot of NullPointerExceptions in the above lines of code.



回答2:

Java has 5 different boolean compare operators: &, &&, |, ||, ^

& and && are \"and\" operators, | and || \"or\" operators, ^ is \"xor\"

The single ones will check every parameter, regardless of the values, before checking the values of the parameters. The double ones will first check the left parameter and its value and if true (||) or false (&&) leave the second one untouched. Sound compilcated? An easy example should make it clear:

Given for all examples:

 String aString = null;

AND:

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

Both parameters are checked before the evaluation is done and a NullPointerException will be thrown for the second parameter.

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

The first parameter is checked and it returns false, so the second paramter won\'t be checked, because the result is false anyway.

The same for OR:

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

Will raise NullPointerException, too.

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

The first parameter is checked and it returns true, so the second paramter won\'t be checked, because the result is true anyway.

XOR can\'t be optimized, because it depends on both parameters.



回答3:

No it will not be checked. This behaviour is called short-circuit evaluation and is a feature in many languages including Java.



回答4:

All the answers here are great but, just to illustrate where this comes from, for questions like this it\'s good to go to the source: the Java Language Specification.

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

The && operator is like & (§15.22.2), but evaluates its right-hand operand only if the value of its left-hand operand is true. [...] At run time, the left-hand operand expression is evaluated first [...] if the resulting value is false, the value of the conditional-and expression is false and the right-hand operand expression is not evaluated. If the value of the left-hand operand is true, then the right-hand expression is evaluated [...] the resulting value becomes the value of the conditional-and expression. Thus, && computes the same result as & on boolean operands. It differs only in that the right-hand operand expression is evaluated conditionally rather than always.

And similarly, Section 15:24, Conditional-Or operator (||), says:

The || operator is like | (§15.22.2), but evaluates its right-hand operand only if the value of its left-hand operand is false. [...] At run time, the left-hand operand expression is evaluated first; [...] if the resulting value is true, the value of the conditional-or expression is true and the right-hand operand expression is not evaluated. If the value of the left-hand operand is false, then the right-hand expression is evaluated; [...] the resulting value becomes the value of the conditional-or expression. Thus, || computes the same result as | on boolean or Boolean operands. It differs only in that the right-hand operand expression is evaluated conditionally rather than always.

A little repetitive, maybe, but the best confirmation of exactly how they work. Similarly the conditional operator (?:) only evaluates the appropriate \'half\' (left half if the value is true, right half if it\'s false), allowing the use of expressions like:

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

without a NullPointerException.



回答5:

No, if a is true (in a or test), b will not be tested, as the result of the test will always be true, whatever is the value of the b expression.

Make a simple test:

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

will not throw a NullPointerException!



回答6:

Short circuit here means that the second condition won\'t be evaluated.

If ( A && B ) will result in short circuit if A is False.

If ( A && B ) will not result in short Circuit if A is True.

If ( A || B ) will result in short circuit if A is True.

If ( A || B ) will not result in short circuit if A is False.



回答7:

No it won\'t, Java will short-circuit and stop evaluating once it knows the result.



回答8:

Yes, the short-circuit evaluation for boolean expressions is the default behaviour in all the C-like family.

An interesting fact is that Java also uses the & and | as logic operands (they are overloaded, with int types they are the expected bitwise operations) to evaluate all the terms in the expression, which is also useful when you need the side-effects.



回答9:

This goes back to the basic difference between & and &&, | and ||

BTW you perform the same tasks many times. Not sure if efficiency is an issue. You could remove some of the duplication.

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