What is short circuiting in java

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 be false regardless of the value there
  • true || . — it is not necessary to know what the right-hand side is because the result can only be true 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

is equivalent to ( && has a higher precedence)

Читайте также:  Javascript свернуть развернуть div

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 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 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 is true and the right-hand operand expression is not evaluated.

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 bList = new ArrayList<>();
boolean result = bList.stream().allMatch(b -> b);

Источник

Java 8 Streams — Short circuiting operations

Java 8 short-circuiting operations are just like boolean short-circuit evaluations in Java.

In boolean short-circuiting logic, for example firstBoolean && secondBoolean , if firstBoolean is false then the remaining part of the expression is ignored (the operation is short-circuited) because the remaining evaluation will be redundant. Similarly in firstBoolean || secondBoolean , if firstBoolean is true the remaining part is short-circuited.

Java 8 Stream short-circuit operations are not limited to boolean types. There are pre defined short-circuiting operations.

Java 8 stream intermediate and terminal operations both can be short circuiting.

Intermediate short-circuiting methods

Intermediate short-circuiting methods cause a stream to operate on a reduced size.

No actual iteration of the elements occur on calling these intermediate methods until the terminal operation is performed.

For example, if some intermediate short-circuiting method reduce the stream size to 0, the pipeline won’t stop processing until the terminal step is executed and that’s where intermediate lambdas are evaluated to yield a terminal result.

Following is the only one intermediate-short-circuiting method currently defined in Stream interface:

    Stream limit(long maxSize)
    Returns a new stream created from this stream, truncated to be no longer than maxSize in length. Following example shows the difference between using limit() and not using limit():

package com.logicbig.example; import java.util.Arrays; import java.util.stream.IntStream; public class LimitExample < public static void main (String[] args) < int[] ints = ; System.out.printf("Source: %s%n", Arrays.toString(ints)); System.out.println("Finding even numbers."); runWithoutLimit(Arrays.stream(ints)); runWithLimit(Arrays.stream(ints)); > private static void runWithoutLimit (IntStream stream) < System.out.println("Running without limit()"); //filter even numbers stream.filter(i ->i % 2 == 0) .forEach(System.out::println); > private static void runWithLimit (IntStream stream) < System.out.println("Running with limit(2)"); //filter even numbers stream.filter(i ->i % 2 == 0) .limit(2) .forEach(System.out::println); > >

Output:

Source: [1, 2, 3, 4, 5, 6] Finding even numbers. Running without limit() 2 4 6 Running with limit(2) 2 4

Note: In above example we are creating and passing new stream instance from the same source to the methods, runWithLimit(..) and runWithoutLimit(..). A stream cannot be reused after a terminal operation is called.

Infinite streams and limit() method

limit(..) method is typically used, when there’s an infinite input, e.g. when a stream created with static methods like Stream generate(Supplier s) or Stream iterate(T seed, UnaryOperator f) . Calling limit() method produces a finite stream as a result. Following example will terminate after 5 elements.

Stream stream = Stream.iterate(1, i -> i + 1); stream.filter(i -> i % 2 == 0) .limit(5) .forEach(System.out::println);

Output:

If we remove limit(5) part, it will be printing even numbers forever. An infinite streams is desirable where size of the data source is not known in advance, for example, data coming as messages from a remote location or data generated to show some GUI animations.
In above example, what if we use the limit(5) first and then apply the filter later? It’s not relevant to the current topic but just see the outcome:

Stream stream = Stream.iterate(1, i -> i + 1); stream.limit(5) .filter(i -> i % 2 == 0) .forEach(System.out::println);

Output:

Terminal short-circuiting methods

These terminal-short-circuiting methods can finish before transversing all the elements of the underlying stream.

A short-circuiting terminal operation, when operating on infinite input data source, may terminate in finite time.

Following are the terminal-short-circuiting methods defined in Stream interface:

    Optional findFirst() :
    Returns the very first element (wrapped in Optional object) of this stream and before transversing the other. Following example shows a InStream of predefined elements which is meant to return only multiples of 3 results. The terminal operation terminated on finding the first element, hence short-circuited.

IntStream stream = IntStream.of(1, 2, 3, 4, 5, 6); stream = stream.filter(i -> i % 3 == 0); OptionalInt opt = stream.findFirst(); if (opt.isPresent())

Output:

The behavior of this operation is explicitly nondeterministic; it is free to select any element in the stream. This is to allow for maximal performance in parallel operations; the cost is that multiple invocations on the same source may not return the same result. (If a stable result is desired, use findFirst() instead.

A deterministic operation will always produces the same output for a given input, regardless of we use parallel or sequential pipeline. Except for operations identified as explicitly nondeterministic, such as findAny(), whether a stream executes sequentially or in parallel should not change the result of the computation. For a sequential stream there won’t be any difference between ‘findFirst’ and ‘findAny’. But for a parallel stream findAny will return ‘any’ element rather than waiting for the ‘first’ element. Following example uses a parallel stream. I’m getting output of ‘6’ instead of ‘2’ on my machine. The result might also vary on multiple executions.

IntStream stream = IntStream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) .parallel(); stream = stream.filter(i -> i % 2 == 0); OptionalInt opt = stream.findAny(); if (opt.isPresent())

Output:

Stream stream = Stream.of("one", "two","three", "four"); boolean match = stream.anyMatch(s -> s.contains("our")); System.out.println(match);
Stream stream = Stream.of("one", "two", "Three", "four"); boolean match = stream.allMatch(s -> s.length() > 0 && Character.isLowerCase(s.charAt(0))); System.out.println(match);
Stream stream = Stream.of("one", "two", "three", "four"); boolean match = stream.noneMatch(s -> s.length() > 0 && Character.isUpperCase(s.charAt(0))); System.out.println(match);

Dependencies and Technologies Used:

Источник

Оцените статью