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

后端 未结 5 1371
你的背包
你的背包 2020-12-13 23:48

I would like to do the following:

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

but in a way that the resu

相关标签:
5条回答
  • 2020-12-13 23:53

    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())

    0 讨论(0)
  • 2020-12-13 23:59

    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());
    
    0 讨论(0)
  • 2020-12-14 00:02

    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).

    0 讨论(0)
  • 2020-12-14 00:06

    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).

    0 讨论(0)
  • 2020-12-14 00:18

    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.

    0 讨论(0)
提交回复
热议问题