Java 8 - omitting tedious collect method

JavaJava 8Java Stream

Java Problem Overview


Java 8 stream api is very nice feature and I absolutely like it. One thing that get's on my nerves is that 90% of the time I want to have input as a collection and output as collections. The consequence is I have to call stream() and collect() method all the time:

collection.stream().filter(p->p.isCorrect()).collect(Collectors.toList());

Is there any java api that would let me skip the stream and directly operate on collections (like linq in c#?):

collection.filter(p->p.isCorrect)

Java Solutions


Solution 1 - Java

Yes, using Collection#removeIf(Predicate):

>Removes all of the elements of this collection that satisfy the given predicate.

Note that it will change the given collection, not return a new one. But you can create a copy of the collection and modify that. Also note that the predicate needs to be negated to act as a filter:

public static <E> Collection<E> getFilteredCollection(Collection<E> unfiltered,
                                                      Predicate<? super E> filter) {
    List<E> copyList = new ArrayList<>(unfiltered);

    // removeIf takes the negation of filter 
	copyList.removeIf(e -> { return !filter.test(e);});  

    return copyList;
}

But as @Holger suggests in the comments, if you choose to define this utility method in your code and use it everywhere you need to get a filtered collection, then just delegate the call to the collect method in that utility. Your caller code will then be more concise.

public static <E> Collection<E> getFilteredCollection(Collection<E> unfiltered,
                                                      Predicate<? super E> filter) {
   return unfiltered.stream()
                    .filter(filter)
                    .collect(Collectors.toList());
}

Solution 2 - Java

You might like using StreamEx

StreamEx.of(collection).filter(PClass::isCorrect).toList();

This has the advantages of being slightly more brief while keeping immutability.

Solution 3 - Java

If you want to operate on collections Guava's FluentIterable is a way to go!

Example (get id's of 10 first vip customers):

FluentIterable
       .from(customers)
       .filter(customer -> customer.isVIP())
       .transform(Client::getId)
       .limit(10);

Solution 4 - Java

If you need a filtered view without modifying the original collection, consider Guava's Collections2.filter().

Solution 5 - Java

Streams had a well defined architecture going in, which you can read a lot about. You might want to read about that before you start down this road.

But why not implement a collection, that implements a similar stream interface that wraps up that code for you?

public class StreamableCollection implements Collection, Stream {
...
}

Then you could do some tricky assumptions for your use case. You could still open a stream from the collections interface, but you could also jump straight in and then on the inside of that handle the opening of the stream I suppose.

    streamableCollection cs = new streamableCollection();
    cs.filter();
    cs.stream();

Your IDE will hop you right to implementing everything... just pass everything back to the default implementations.

Solution 6 - Java

I also think the Stream API is good, but verbose for short operations. I've used these utility methods in a few projects:

import java.util.List;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class Functions {

	public static <T,V> List<V> map(final List<T> in, final Function<T, V> function) {
		return in == null ? null : map(in.stream(), function);
	}

	public static <T,V> List<V> map(final Stream<T> in, final Function<T, V> function) {
		return in == null ? null : in
			.map(function)
			.collect(Collectors.toList());
	}

	public static <T> List<T> filter(final List<T> in, final Predicate<T> predicate) {
		return in == null ? null : filter(in.stream(), predicate);
	}

	public static <T> List<T> filter(final Stream<T> in, final Predicate<T> predicate) {
		return in == null ? null : in
			.filter(predicate)
			.collect(Collectors.toList());
	}
}

This lets me do e.g.

List<String> wrapped = Functions.map(myList, each -> "[" + each + "]");

Normally I static import the method as well.

Solution 7 - Java

If you are open to using a third party library, you could use Eclipse Collections which has rich APIs directly available under collections. Your example can be written as below with Eclipse Collections.

collection.select(p->p.isCorrect)
collection.select(MyClass::isCorrect)

Note: I am a committer for Eclipse Collections.

Solution 8 - Java

You might try this, from the guava library. It seems a little less cluttered than the Stream approach.

 ImmutableList.copyOf(Iterables.filter(collection, MyClass::isCorrect));

See https://stackoverflow.com/questions/6176918/google-collections-guava-libraries-immutableset-list-map-and-filtering for a discussion on the technique.

Solution 9 - Java

Yes, there are several libraries that address Java 8's stream verbosity. An incomplete list:

My preference goes with jOOL. I've been using it in my last projects. The others I know but I didn't really use so I can't give you an impression.

Your example with jOOL would be:

Seq.seq(collection).filter(p->p.isCorrect()).toList();

Solution 10 - Java

With cyclops-react you have a number of options.

We can make use of Lazy Extended Collections

  CollectionX<String> collection = ListX.of("hello","world");
  CollectionX<String> filtered = collection.filter(p->p.isCorrect());

There is support for mutable, immutable and persistent extended collections. Functional operations on collections are lazy (i.e. behave like replayable Streams) and are materialized only on first access.

We can make use of a powerful extened Stream type

  ReactiveSeq.fromIterable(collection)
             .filter(p->p.isCorrect())
             .toList();

[Disclosure I am the lead developer of cyclops-react]

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser3364192View Question on Stackoverflow
Solution 1 - JavaM AView Answer on Stackoverflow
Solution 2 - JavaGuiSimView Answer on Stackoverflow
Solution 3 - JavaJakub DziworskiView Answer on Stackoverflow
Solution 4 - JavashmoselView Answer on Stackoverflow
Solution 5 - JavaTheNorthWesView Answer on Stackoverflow
Solution 6 - JavaRory HunterView Answer on Stackoverflow
Solution 7 - JavaitohroView Answer on Stackoverflow
Solution 8 - JavaHank DView Answer on Stackoverflow
Solution 9 - JavasargueView Answer on Stackoverflow
Solution 10 - JavaJohn McCleanView Answer on Stackoverflow