我怎样才能收集一个Java 8stream到一个番石榴ImmutableCollection?

我想要做以下事情:

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

但是结果列表是番石榴ImmutableList列表的实现。

我知道我可以做

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

但我想直接收集。 我试过了

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

但它抛出了一个例外:

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

这是collectAndThen collectingAndThen器有用的地方:

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

它将转换应用于刚刚创build的List ; 导致ImmutableList


或者你可以直接收集到Builder ,最后调用build()

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

如果这个选项对你来说有点冗长,并且你想在很多地方使用它,你可以创build你自己的收集器:

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

接着:

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

以防链接消失在评论中; 我的第二种方法可以在一个简单的使用Collector.of的静态工具方法中定义。 这比创build自己的Collector类更简单。

 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); } 

和用法:

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

Alexis公认的答案中的toImmutableList()方法现在包含在Guava 21中 ,可以用作:

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

虽然不是直接回答我的问题(它不使用收集器),但这是一个相当优雅的方法,不使用中间集合:

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

来源 。

仅供参考,在没有Java 8的Guava中有一个合理的方法:

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

如果你实际上不需要List语义,并且可以使用NavigableSet ,那甚至更好,因为ContiguousSet不必实际存储所有元素(只是RangeDiscreteDomain )。