Is the skip() method a short circuiting-operation?
Asked Answered
L

2

9

I am reading about Java streams' short-circuiting operations and found in some articles that skip() is a short-circuiting operation.

In another article they didn't mention skip() as a short-circuiting operation.

Now I am confused; is skip() a short-circuiting operation or not?

Levalloisian answered 28/7, 2018 at 13:37 Comment(0)
C
17

From the java doc under the "Stream operations and pipelines" section :

An intermediate operation is short-circuiting if, when presented with infinite input, it may produce a finite stream as a result. A terminal operation is short-circuiting if, when presented with infinite input, it may terminate in finite time.

Emphasis mine.

if you were to call skip on an infinite input it won't produce a finite stream hence not a short-circuiting operation.

The only short-circuiting intermediate operation in JDK8 is limit as it allows computations on infinite streams to complete in finite time.

Example:

if you were to execute this program with the use of skip:

String[] skip = Stream.generate(() -> "test") // returns an infinite stream
                      .skip(20) 
                      .toArray(String[]::new);

it will not produce a finite stream hence you would eventually end up with something along the lines of "java.lang.OutOfMemoryError: Java heap space".

whereas if you were to execute this program with the use of limit, it will cause the computation to finish in a finite time:

String[] limit = Stream.generate(() -> "test") // returns an infinite stream
                       .limit(20)
                       .toArray(String[]::new);
Clayborne answered 28/7, 2018 at 13:48 Comment(2)
there's one more besides limit, here : https://mcmap.net/q/169406/-is-the-skip-method-a-short-circuiting-operationCloakroom
@Cloakroom limit is the only one in jdk8 which is what the question is tagged with. I guess I'll make it more clear by stating this in the answer.Clayborne
C
6

Just want to add my two cents here, this idea in general of a short-circuiting a stream is infinitely complicated (at least to me and at least in the sense that I have to scratch my head twice usually). I will get to skip at the end of the answer btw.

Let's take this for example:

Stream.generate(() -> Integer.MAX_VALUE);

This is an infinite stream, we can all agree on this. Let's short-circuit it via an operation that is documented to be as such (unlike skip):

Stream.generate(() -> Integer.MAX_VALUE).anyMatch(x -> true);

This works nicely, how about adding a filter:

Stream.generate(() -> Integer.MAX_VALUE)
      .filter(x -> x < 100) // well sort of useless...
      .anyMatch(x -> true);

What will happen here? Well, this never finishes, even if there is a short-circuiting operation like anyMatch - but it's never reached to actually short-circuit anything.

On the other hand, filter is not a short-circuiting operation, but you can make it as such (just as an example):

someList.stream()
        .filter(x -> {
           if(x > 3) throw AssertionError("Just because");            
})

Yes, it's ugly, but it's short-circuiting... That's how we (emphases on we, since lots of people, disagree) implement short-circuiting reduce - throw an Exception that has no stack traces.

In java-9 there was an addition of another intermediate operation that is short-circuiting: takeWhile that acts sort of like limit but for a certain condition.

And to be fair, the bulk of the answer about skip was an already give by Aomine, but the most simple answer is that it is not documented as such. And in general (there are cases when documentation is corrected), but that is the number one indication you should look at. See limit and takeWhile for example that clearly says:

This is a short-circuiting stateful intermediate operation

Cloakroom answered 28/7, 2018 at 21:25 Comment(6)
when you say "the most simple answer is that it is not documented as such". as well as that being true, I believe the quote of "An intermediate operation is short-circuiting if, when presented with infinite input, it may produce a finite stream, as a result" is more than enough for me. +1Clayborne
@Aomine you are right, problem is that this is package documentation and considering how badly that is handled in IDE's usually, it is read on sparsely. You usually read only the method documentation itselfCloakroom
I guess I consider myself one of those people who always read the package documentation first before moving on to the method documentation. That said, being more explicit in the method doc would also make things a little bit better for some people I guess. remember this post a while back we answered on iterator() on parallel stream guarantee encounter order?, you had to look really deep to find the answer only until Stuart Marks to say it was an oversight in the specificationClayborne
I don't mean to spam the chat :), but where I said "you had to look really deep" should really have been "one had to look really deep" as I wasn't referring to you but rather the people in general.Clayborne
@Aomine I did not even notice (or care) to begin with... all good!Cloakroom
@Aomine well, there are a lot of underspecified things, especially with the Stream API and still, to many people did not read the package documentation or even the class documentation. But to be fair to those developers, I have the strong feeling that the javadoc maintainers do not assume that anyone is still reading these awful frameset-html pages, especially after the introduction of modules, it’s an unnavigable mess and even internal links are often broken and no-one seems to care…Delorenzo

© 2022 - 2024 — McMap. All rights reserved.