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.
Why use short-circuit code?
For programmers, the benefit of a less verbose syntax over another more verbose syntax can be:
- less to type, therefore higher coding efficiency
- less to read, therefore better maintainability.
Now I'm only talking about when the less verbose syntax is not tricky or clever in any way, just the same recognized way of doing, but in fewer characters.
It's often when you see specific constructs in one language that you wish the language you use could have, but didn't even necessarily realize it before. Some examples off the top of my head:
- anonymous inner classes in Java instead of passing a pointer to a function (way more lines of code).
- in Ruby, the ||= operator, to evaluate an expression and assign to it if it evaluates to false or is null. Sure, you can achieve the same thing by 3 lines of code, but why?
- and many more...
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.
Would this be an example of short circuiting?
Yes, this is a valid example of using short-circuiting correctly:
if(customerIndex < 0 || customerIndex >= 5 || customers[customerIndex] == null)
This code works only under the assumption that ||
stops evaluating as soon as it gets a true
- otherwise, customers[customerIndex]
could be reached with an invalid index, triggering an exception.
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.
programming with short-circuit evaluation in Java
I would refactor it and write it like this:
char[] values = {'x', 'y', 'z', 't'};
for (char c : values) {
Bar bar = peekAndGet(c);
if (bar != null) return produce(bar);
}
return null;
Note: one good reason to do it, is that the first time I read your code I thought it looked buggy until I read your question. You want to keep those "Something looks wrong" moments for things that really are wrong.
Avoiding exceptions by short circuiting
It's a common practice to use short-circuit operator to avoid exceptions. And it is obviously standard.
JLS Section 15.24 - Conditional OR operator:
The conditional-or operator || operator is like | (§15.22.2), but
evaluates its right-hand operand only if the value of its left-hand
operand is false.
- ConditionalOrExpression:
- ConditionalAndExpression
- ConditionalOrExpression || ConditionalAndExpression
Given your case, it would be pretty more clear if you use Conditional && operator and change your condition to:
if (i < a.length - 1 && a[i] != a[i + 1])
The intention is more clear in this code on the first look. Frankly speaking I had to go through twice over your condition to figure out what is it doing.
Again not related to concrete question, I'll modify your for loop to use maximum index one less than you are using currently, to avoid the conditional operator entirely:
for (int i = 0; i < a.length - 1; i++) {
if (a[i] != a[i + 1]) {
System.out.println("now what : " + a[i]);
list.add(i);
}
}
Some Common Examples:
Some quite common examples where you would see the use of conditional operators to avoid exceptions are:
Overriding equals()
method:
public boolean equals(Object obj) {
return obj instanceof MyClass && ((MyClass)obj).num == this.num;
}
Handling null
reference in some method invocation:
// Although there are better way to do this.
if (str != null && str.equals(str2)) {
// some code
}
Avoiding division by zero:
if (x != 0 && 4/x > 1) {
// some code
}
Contrary to this, all the above codes will throw exception at runtime, if you use Boolean Logical Operator, and the first expression evaluates to false
.
Benefits of using short-circuit evaluation
Short-circuiting boolean expressions are exactly equivalent to some set of nested ifs, so are as efficient as that would be.
If b doesn't have side-effects, it can still be executed in parallel with a (for any value of "in parallel", including pipelining).
If b has side effects which the CPU architecture can't cancel when branch prediction fails then yes, this might require delays which wouldn't be there if both sides were always evaluated. So it's something to look at if you do ever find that short-circuiting operators are creating a performance bottleneck in your code, but not worth worrying about otherwise.
But short-circuiting is used for control flow as much as to save unnecessary work. It's common among languages I've used, for example the Perl idiom:
open($filename) or die("couldn't open file");
the shell idiom:
do_something || echo "that failed"
or the C/C++/Java/etc idiom:
if ((obj != 0) && (obj->ready)) { do_something; } // not -> in Java of course.
In all these cases you need short-circuiting, so that the RHS is only evaluated if the LHS dictates that it should be. In such cases there's no point comparing performance with alternative code that's wrong!
Related Topics
How to Fix the "Java.Security.Cert.Certificateexception: No Subject Alternative Names Present" Error
Java List.Add() Unsupportedoperationexception
Differencebetween Integer and Int in Java
How to Add Jradiobutton to Group in Jtable
How to Lock Compiled Java Classes to Prevent Decompilation
Java: Notify() VS. Notifyall() All Over Again
Iterating Over and Removing from a Map
What Is the "Owning Side" in an Orm Mapping
Is Method Reference Caching a Good Idea in Java 8
Arithmeticexception: "Non-Terminating Decimal Expansion; No Exact Representable Decimal Result"
How to Read and Copy the Http Servlet Response Output Stream Content for Logging
Handling Passwords Used for Auth in Source Code
Embed Java into a C++ Application
Embedding Java Applet into .HTML File
How to Store Date/Time and Timestamps in Utc Time Zone with JPA and Hibernate