Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I skip the limit(number) call with a stream when the number equals 0?

I have some Java code that provides objects from items. It limits them based on the maxNumber:

items.stream()
     .map(this::myMapper)
     .filter(item -> item != null)
     .limit(maxNumber)
     .collect(Collectors.toList());

It works properly, but the question is this: Is there a way of skipping the limiting when the maxNumber == 0?

I know I could do this:

if (maxNumber == 0) {
    items.stream()
         .map(this::myMapper)
         .filter(item -> item != null)
         .collect(Collectors.toList());
} else {
    items.stream()
         .map(this::myMapper)
         .filter(item -> item != null)
         .limit(maxNumber)
         .collect(Collectors.toList());
}

But perhaps there's a better way, does anything come to your mind?

like image 292
randomuser1 Avatar asked Mar 12 '20 08:03

randomuser1


People also ask

How do I use skip in stream?

The skip() MethodThe skip(n) method is an intermediate operation that discards the first n elements of a stream. The n parameter can't be negative, and if it's higher than the size of the stream, skip() returns an empty stream. When this stream is executed, the forEach starts asking for items.

How do I skip the first element in a stream?

Stream skip(n) method is used to skip the first 'n' elements from the given Stream. The skip() method returns a new Stream consisting of the remaining elements of the original Stream, after the specified n elements have been discarded in the encounter order.

How does stream limit work?

Stream limit(n) is used to retrieve a number of elements from the Stream while the count must not be greater than n. The limit() method returns a new Stream consisting of the elements of the given stream, truncated to be no longer than maxSize in length.

Can Java streams be of infinite size?

We can create an infinite stream of any custom type elements by passing a function of a Supplier interface to a generate() method on a Stream.


2 Answers

No, the stream pipeline doesn't allow to actually skip around any part of the pipeline, so you're forced to work with either conditional logic inside the steps and including the limit() always in the pipeline, or building the stream in parts which would be a bit more legible (IMHO) than the if/else in the question

Stream<Item> s = items.stream()
         .map(this::myMapper)
         .filter(Objects::nonNull);

if(maxNumber > 0) {
    s = s.limit(maxNumber);
}

List<Item> l = s.collect(Collectors.toList());

In a simple case like here it doesn't make much difference, but you often see in regular code collections being passed through methods, converted to streams and then back to collections. In such cases it might be a better idea to work with streams in parts until you really need to collect().

like image 125
Kayaman Avatar answered Oct 20 '22 05:10

Kayaman


I suppose that

.limit(maxNumber == 0 ? Long.MAX_VALUE : maxNumber)

will do the trick, as it is highly non probable that you are going to tackle a stream with more than 2^63-1 elements...

At least be careful with parallel streams on this... A note in API docs says:

API Note: While limit() is generally a cheap operation on sequential stream pipelines, it can be quite expensive on ordered parallel pipelines, especially for large values of maxSize...

like image 40
Jean-Baptiste Yunès Avatar answered Oct 20 '22 07:10

Jean-Baptiste Yunès