Java logical operator short-circuiting
The &&
and ||
operators "short-circuit", meaning they don't evaluate the right-hand side if it isn't necessary.
The &
and |
operators, when used as logical operators, always evaluate both sides.
There is only one case of short-circuiting for each operator, and they are:
false && ...
- it is not necessary to know what the right-hand side is because the result can only befalse
regardless of the value theretrue || ...
- it is not necessary to know what the right-hand side is because the result can only betrue
regardless of the value there
Let's compare the behaviour in a simple example:
public boolean longerThan(String input, int length) {
return input != null && input.length() > length;
}
public boolean longerThan(String input, int length) {
return input != null & input.length() > length;
}
The 2nd version uses the non-short-circuiting operator &
and will throw a NullPointerException
if input
is null
, but the 1st version will return false
without an exception.
Java logical operator (&&, ||) short-circuit mechanism
It's simply because
if (false && true || true)
is equivalent to (&&
has a higher precedence)
if ((false && true) || true)
which is
if (false || true)
which is... true
.
Note: In the expression true || true && false
, the part true && false
is called a dead code because it doesn't affect the final result of the evaluation, since true || anything
is always true
.
It is worth mentioning that there exist &
and |
operators that can be applied to booleans, they are much like &&
and ||
except that they don't short circuit, meaning that if you have the following expression:
if (someMethod() & anotherMethod())
and someMethod
returns false
, anotherMethod
will still be reached! But the if
won't be executed because the final result will be evaluated to false
.
Logical operator OR without short circuit
One example arises if we have two functions and we want them both to be executed:
if (foo() | bar())
If we had used ||
, then bar()
will not be executed if foo()
returns true, which may not be what we want.
(Although this is somewhat of an obscure case, and more often than not ||
is the more appropriate choice.)
An analogous situation can come up with &
/&&
:
if (foo() & bar())
If we had used &&
, then bar()
will not be executed if foo()
returns false, which again may not be what we want.
Short circuit vs non short circuit operators
One reason you might want to use the non-short-circuiting operator is if you are somehow depending on side-effects of functions. For example.
boolean isBig(String text) {
System.out.println(text);
return text.length() > 10;
}
...
if( isBig(string1) || isBig(string2) ){
...
}
If you don't care about whether the println
is executed then you should use the short circuit operations as above. However, if you want both strings to be printed always (thus depending on side effects) then you need to use the non-short-circuit operator.
Practically speaking, you almost always want to use the short-circuit operators. Relying on side effects in expressions is usually bad programming practice.
One exception is in very low level or performance-sensitive code. The short-circuiting operators can be slightly slower because they cause branching in the program execution. Also using bitwise operators allows you to do 32 or 64 parallel boolean operations as a single integer operation, which is very fast.
Mixing short-circuit operators with other operators
The short-circuiting logical operators don't even evaluate the right side when short-circuiting. This is covered by the JLS, Section 15.24, which covers the ||
operator.
At run time, the left-hand operand expression is evaluated first; if the result has type
Boolean
, it is subjected to unboxing conversion (§5.1.8).If the resulting value is
true
, the value of the conditional-or expression istrue
and the right-hand operand expression is not evaluated.
(bold emphasis mine)
So, the ++y
is never evaluated, and y
remains 0
.
The same short-circuiting behavior exists for the &&
operator when the left side evaluates to false
.
How Java Logical short circuit Operators Work
You have two operators. The AND operator is evaluated first and returns false
. Then the OR operator is evaluated and returns true
, since the second operand of the OR operator is true:
if (line.length() > 0 && !line.startsWith("/*") || !line.startsWith("--"))
false && not evaluated
false || true
true
If you want the second operand of the AND operator to include the OR operator, you should add parentheses:
if (line.length() > 0 && (!line.startsWith("/*") || !line.startsWith("--")))
false not evaluated
false
What is short circuiting and how is it used when programming in Java?
Short-circuiting is where an expression is stopped being evaluated as soon as its outcome is determined. So for instance:
if (a == b || c == d || e == f) {
// Do something
}
If a == b
is true, then c == d
and e == f
are never evaluated at all, because the expression's outcome has already been determined. if a == b
is false, then c == d
is evaluated; if it's true, then e == f
is never evaluated. This may not seem to make any difference, but consider:
if (foo() || bar() || baz()) {
// Do something
}
If foo()
returns true, then bar
and baz
are never called, because the expression's outcome has already been determined. So if bar
or baz
has some other effect than just returning something (a side effect), those effects never occur.
One great example of short-circuiting relates to object references:
if (a != null && a.getFoo() != 42) {
// Do something
}
a.getFoo()
would normally throw a NullPointerException
if a
were null
, but because the expression short-circuits, if a != null
is false
, the a.getFoo()
part never happens, so we don't get an exception.
Note that not all expressions are short-circuited. The ||
and &&
operators are short-circuited, but |
and &
are not, nor are *
or /
; in fact most operators are not.
Java short circuit evaluation
Advanced debugging lesson #1:
If you run into a seemingly impossible error (e.g. one that contradicts you knowledge about Java), do the following:
Consult a reputable text book (or better still, the relevant standard) to confirm that your understanding is not flawed. (In this case your understanding was correct, and any half-decent textbook would confirm this in a minute.)
Check all of the stupid things that you could have done that could cause the impossible error. Things like not saving a file, not doing a complete build, running an old / stale version of the application, being in the wrong directory, and so on.
In summary, learn to doubt yourself a bit more.
Short circuit logical operators over Iterable
Use Stream.allMatch which is a short-circuiting operation.
List<Boolean> bList = new ArrayList<>();
boolean result = bList.stream().allMatch(b -> b);
Related Topics
How to Set Java_Home on Windows 7
How to Increment a Date by One Day in Java
Generating Unique Random Numbers in Java
How to Reverse an Int Array in Java
Correct Way to Add External Jars (Lib/*.Jar) to an Intellij Idea Project
Read/Write to Windows Registry Using Java
Infinite Recursion With Jackson Json and Hibernate JPA Issue
Difference Between Jsf, Servlet and Jsp
:: (Double Colon) Operator in Java 8
Java 256-Bit Aes Password-Based Encryption
Is There an Eval() Function in Java
How to Read All Files in a Folder from Java
How to Create Recyclerview With Multiple View Types
What Is Reflection and Why Is It Useful