How can I collect a Java 8 stream into a Guava ImmutableCollection?

java stream immutable
java stream collect
java stream map
unmodifiablelist java 8
java-stream<map to map
java collectors
guava immutableset
java immutablelist filter

I would like to do the following:

List<Integer> list = IntStream.range(0, 7).collect(Collectors.toList());

but in a way that the resulting list is an implementation of Guava's ImmutableList.

I know I could do

List<Integer> list = IntStream.range(0, 7).collect(Collectors.toList());
List<Integer> immutableList = ImmutableList.copyOf(list);

but I would like to collect to it directly. I've tried

List<Integer> list = IntStream.range(0, 7)
    .collect(Collectors.toCollection(ImmutableList::of));

but it threw an exception:

java.lang.UnsupportedOperationException at com.google.common.collect.ImmutableCollection.add(ImmutableCollection.java:96)

The toImmutableList() method in the accepted answer of Alexis is now included in Guava 21 and can be used as:

ImmutableList<Integer> list = IntStream.range(0, 7)
    .boxed()
    .collect(ImmutableList.toImmutableList());

Edit: Removed @Beta from ImmutableList.toImmutableList along with other frequently used APIs in Release 27.1 (6242bdd).

Collect a Java Stream to an Immutable Collection, This is where the collectingAndThen collector is useful: List<Integer> list = IntStream.range(0, 7).boxed() .collect(collectingAndThen(toList(),  How can I collect a Java 8 stream into a Guava ImmutableCollection? (4) BTW: since JDK 10 it can be done in pure Java: List < Integer > list = IntStream. range (0, 7). collect (Collectors. toUnmodifiableList ());

This is where the collectingAndThen collector is useful:

List<Integer> list = IntStream.range(0, 7).boxed()
                .collect(collectingAndThen(toList(), ImmutableList::copyOf));

It applies the transformation to the List you just built; resulting in an ImmutableList.


Or you could directly collect into the Builder and call build() at the end:

List<Integer> list = IntStream.range(0, 7)
                .collect(Builder<Integer>::new, Builder<Integer>::add, (builder1, builder2) -> builder1.addAll(builder2.build()))
                .build();

If this option is a bit-verbose to you and you want to use it in many places, you can create your own collector:

class ImmutableListCollector<T> implements Collector<T, Builder<T>, ImmutableList<T>> {
    @Override
    public Supplier<Builder<T>> supplier() {
        return Builder::new;
    }

    @Override
    public BiConsumer<Builder<T>, T> accumulator() {
        return (b, e) -> b.add(e);
    }

    @Override
    public BinaryOperator<Builder<T>> combiner() {
        return (b1, b2) -> b1.addAll(b2.build());
    }

    @Override
    public Function<Builder<T>, ImmutableList<T>> finisher() {
        return Builder::build;
    }

    @Override
    public Set<Characteristics> characteristics() {
        return ImmutableSet.of();
    }
}

and then:

List<Integer> list = IntStream.range(0, 7)
                              .boxed()
                              .collect(new ImmutableListCollector<>());

Just in case the link disappears in the comments; my second approach could be defined in a static utility method that simply uses Collector.of. It's simpler than creating your own Collector class.

public static <T> Collector<T, Builder<T>, ImmutableList<T>> toImmutableList() {
    return Collector.of(Builder<T>::new, Builder<T>::add, (l, r) -> l.addAll(r.build()), Builder<T>::build);
}

and the usage:

 List<Integer> list = IntStream.range(0, 7)
                               .boxed()
                               .collect(toImmutableList());

Make ImmutableCollection.Builder Java8-Collector-friendly · Issue , Learn how to collect Java Streams to immutable Collections. We are going to make use of the Google's Guava library to drive some of 8. 9. 10. public static <​T, A extends List<T>> Collector<T, A, List<T>> toImmutableList(. 3. Using Java's collectingAndThen() The collectingAndThen() method from Java's Collectors class accepts a Collector, and a finisher Function that is applied to the result returned from the Collector: Since we can't use the toCollection() Collector directly, we need to collect elements to a temporary list and then construct an immutable list from it.

While not a direct answer to my question (it does not use collectors), this is a fairly elegant approach which doesn't use intermediate collections:

Stream<Integer> stream = IntStream.range(0, 7).boxed();
List<Integer> list = ImmutableList.copyOf(stream.iterator());

Source.

Guava ImmutableCollections, Multimaps and Java 8 Collectors , Java 8 will also require major changes to Guava given that many new things it provides Is there any reason to favor stream.collect(Collectors. ###Starting a stream StreamSupport is not entirely able to recreate the Java 8 API, for one simple reason: you can’t change the existing Java 7 implementations of the Java standard library. In particular, and most crucially, the java.util.Collection.stream() method can’t be added to Java 7.

BTW: since JDK 10 it can be done in pure Java:

List<Integer> list = IntStream.range(0, 7)
    .collect(Collectors.toUnmodifiableList());

Also toUnmodifiableSet and toUnmodifiableMap available.

Inside collector it was done via List.of(list.toArray())

Guava ImmutableCollections, Multimaps and Java 8 , I would like to do the following: List<Integer> list = IntStream.range(0, 7).collect(​Collectors.toList()); but in a way that the resulting list is an implementation of  * < p >< b >Java 8 users: If you want to convert a {@link java.util.stream.Stream} to a sorted * {@code ImmutableList}, use {@code stream.sorted(comparator).collect(toImmutableList())}. * * @throws NullPointerException if any element in the input is null * @since 21.0 */ public static < E > ImmutableList< E > sortedCopyOf

FYI, there's a reasonable way to do this in Guava without Java 8:

ImmutableSortedSet<Integer> set = ContiguousSet.create(
    Range.closedOpen(0, 7), DiscreteDomain.integers());
ImmutableList<Integer> list = set.asList();

If you don't actually need the List semantics and can just use a NavigableSet, that's even better since a ContiguousSet doesn't have to actually store all the elements in it (just the Range and DiscreteDomain).

ImmutableList (Guava: Google Core Libraries for Java 23.0 API), stream package when Java 8 was released. A Collector is used to “collect” the results of stream operations. Results are collected from a stream  If your data has no duplicates, or you wish to deduplicate elements, use ImmutableSortedSet.copyOf(elements); if you want a List you can use its asList() view. Java 8 users: If you want to convert a Stream to a sorted ImmutableList, use stream.sorted().collect(toImmutableList()).

ImmutableList (Guava: Google Core Libraries for Java 23.5-jre API), How to create custome collector interface instances to collect the results of stream operations in Java 8. A Java 8 version of Guava is a long ways off at this point, as Guava currently still targets Java 6. Java 8 will also require major changes to Guava given that many new things it provides are similar or equivalent to things in Guava. This is definitely something that's on our radar for things we do want to add, though.

Immutable List in Java, ImmutableCollection<E> Returns an unmodifiable iterator across the elements in this collection. int, lastIndexOf(Object Java 8 users: If you want to convert a Stream to a sorted ImmutableList , use stream.sorted().collect(toImmutableList()) . Results are collected from a stream when the terminal operation Stream.collect method is called. While there are default implementations available, there are times we’ll want to use some sort of custom container. Our goal today will be to create Collector instances that produce Guava ImmutableCollections and Multimaps.

ImmutableCollection<E> Returns an unmodifiable iterator across the elements in this collection. int, lastIndexOf(Object Java 8 users: If you want to convert a Stream to a sorted ImmutableList , use stream.sorted().collect(toImmutableList()) . guava / guava / src / com / google / common / collect / ImmutableMap.java Find file Copy path jlavallee Add @DoNotMock to several com.google.common types 4eea0f7 Dec 9, 2019

Comments
  • The method marked as @Beta. So it's not reccomended apriory by docs ?
  • Still @Beta as of Guava 26.0.
  • This still creates an intermediate list, doesn't it? I would like to avoid that. Could the ImmutableList.Builder be of any help?
  • @Zoltán You could accumulate the values in the builder directly (see edit) and then call build().
  • Thank you for this detailed answer. It seems that this is currently being addressed: github.com/google/guava/issues/1582, there's also a nice example here (a lot like what you suggested): gist.github.com/JakeWharton/9734167
  • @Zoltán Ah yes; good finds; it simply wraps the second alternative into utility methods. A bit better than defining your own Collector class :-)
  • Reference types could be ImmutableList<Integer> (instead of List<Integer>).
  • This is not exactly true, since ImmutableCollections.List12 and ImmutableCollections.ListN != Guava's ImmutableList. From a practical perspective you are mostly correct, but it would still make sense to mention this nuance in your answer.