ChatGPT解决这个技术问题 Extra ChatGPT

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

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?


Z
Zubin Mukerjee

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.


Do bitwise comparisons exist so you can evaluate both expressions? i.e. if(str != null | str.isEmpty()) ? (of course this isn't a practical example, in fact it's stupid, but you get the idea)
As long as the expressions don't have side effects, short-circuit semantics are logically equivalent to complete evaluation. That is, if A is true, you know A||B is true without having to evaluate B. The only time it will make a difference is if an expression has side effects. As for other operators, you can use * and + as logical and and or; ((A?1:0) * (B?1:0)) == 1, ((A?1:0) + (B?1:0)) > 0. You can even do xor: ((A?1:0) + (B?1:0)) == 1.
@Kezzer: is that really bitwise comparison? I think it is a boolean (logical) operator. It's different than the bitwise (integer) operator, despite having the same symbol...
A handy trick when you want to switch between '&&' and '||' expressions is to negate the entire expression, in such way that: !(str != null && !str.isEmpty()) becomes: (str !(!=) null !(&&) !(!)str.isEmpty()) and then: (str == null || str.isEmpty()) because: !(!=) is == !(&&) is || !(!) eliminates itself other helpful negations are: !(<) is >= !(>) is <= and viceversa
H
Hardcoded

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.


"Java has 4 different boolean compare operators: &, &&, |, ||"... You're forgetting ^ (xor).
Oh, I wasn't aware it checks boolean boolean values, too. Only used it for bitmasks, so far.
h
heijp06

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


C
Cowan

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.


G
Gaunt

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.


R
Romain Linsolas

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!


a
abyx

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


f
fortran

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.


This is interesting to remember: e.g. given a method changeData(data) that returns a boolean, then: if (a.changeData(data) || b.changeData(data)) { doSomething(); } doesn't execute changeData on b if a.changeData() returns true, but if (a.changeData(data) | b.changeData(data)) { doSomething() } executes changeData() on both a and b, even if the one invoked on a returned true.
P
Peter Lawrey

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