&&
is a short-circuit operator evaluated from left to right, so if the operand on the left side of &&
operator is evaluated to false, evaluation should not continue. BUT I expected that the ++
should be evaluated before &&
because it has higher precedence, and (from the link):
Operators with higher precedence are evaluated before operators with relatively lower precedence.
In that case, why doesn't count
increment in the third line of this code?
int mask = 2;
int count = 0;
if( !(mask > 1) && ++count > 1) { mask += 100; }
System.out.println(mask + " " + count);
The operator precedence is responsible for evaluating the expressions. In Java, parentheses() and Array subscript[] have the highest precedence in Java. For example, Addition and Subtraction have higher precedence than the Left shift and Right shift operators.
The logical-AND operator ( && ) has higher precedence than the logical-OR operator ( || ), so q && r is grouped as an operand. Since the logical operators guarantee evaluation of operands from left to right, q && r is evaluated before s-- .
Yes, Java follows the standard arithmetic order of operations.
No, the way the expression is evaluated goes from left to right, while taking operator precedence into account. So once in a && b
the a
gets false, b
is not evaluated anymore.
JLS §15.23. Conditional-And Operator && says:
The conditional-and operator
&&
is like&
(§15.22.2), but evaluates its right-hand operand only if the value of its left-hand operand is true.
Here is a detailed step by step evaluation of how this works:
This is because, when you parse an expression as a human being, you start with the lowest precedence operators first. In this case &&
has lower precedence then ++
.
++a < 0 && foo
^^
start
In order to compute the result of &&
, you should know the left operand:
++a < 0 && ++b
^^^^^^^
so compute this
Now, when you want to know the result of ++a < 0
, take a look at the lowest precedence operator first, which is <
:
++a < 0
^
evaluate this
In order to do that, you will need both left and right operand. So compute them:
++a
0
This is the moment were ++a
gets increased.
So, now we are at the bottom. Let's make our way back to the top:
false && foo
And this is where the fact that && is short circuit comes in. Left operand is false, so the right operand expression foo
is not evaluated anymore. Which becomes:
false
without the evaluation of the right operand.
Edit: I missed the point of the question. See revisions for semi-detailed explanation of short-circuit evaluation.
Each operand of the logical-AND and logical-OR operators is a separate expression, and thus, treated independently (given its own order of operators to evaluate, according to correct operator precedence).
So, while ++
has the highest precedence in ++count > 1
, that expression is never even evaluated (because of the short-circuiting).
You seem to be dissatisfied with the short circuit evaluation explanation. Why is precedence not important here?
Imagine this code:
if( !(mask > 1) && Increment(count) > 1)
Function application (that is, calling a function by writing the brackets) is the highest precedence, yet the function call will never happen. If short circuit evaluation made allowances for precedence, it wouldn't really work at all.
To expand a little - operators such as ++ , - , etc all map to function calls. However, the compiler needs to understand the order that they bind. This is not the order that they are evaluated in.
So a + b * c
doesn't mean workout b * c then the sum. It means only this add( a, multiply(b, c))
The order of evaluation is different in the case of && (though not in my example), to make it easier for programmers to write quick code.
To avoid confusion, recall that
if (a && b) {
// do something
}
is semantically the same as:
if (a) {
if (b) {
// do something
}
}
Obviously, if a
evaluates to false, the term b
will never be seen. In particular, an increment opertor there will not execute.
By recalling this expansion, the behaviour should be easier to understand. It's best to consider &&
as a shortcut for above nested-if statement. (In the case of having an else
statement, you will also need to add two copies of the else code, so it's not as easy.)
A more "exact" representation would be to use a condition method:
boolean condition() {
if (!a) return false;
if (!b) return false;
return true;
}
Again, b
will never be evaluated if a
returns false already.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With