我怎样才能收集一个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
不必实际存储所有元素(只是Range
和DiscreteDomain
)。