Java 8 如何将Java 8流收集到Guava ImmutableCollection中?

Java 8 如何将Java 8流收集到Guava ImmutableCollection中?,java-8,guava,java-stream,Java 8,Guava,Java Stream,我想做以下工作: List<Integer> list = IntStream.range(0, 7).collect(Collectors.toList()); 但我想直接向它收款。我试过了 List<Integer> list = IntStream.range(0, 7) .collect(Collectors.toCollection(ImmutableList::of)); List List=IntStream.range(0,7) .collec

我想做以下工作:

List<Integer> list = IntStream.range(0, 7).collect(Collectors.toList());
但我想直接向它收款。我试过了

List<Integer> list = IntStream.range(0, 7)
    .collect(Collectors.toCollection(ImmutableList::of));
List List=IntStream.range(0,7)
.collect(Collectors.toCollection(ImmutableList::of));
但它抛出了一个例外:

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


这就是
采集器的作用,然后
采集器很有用:

List<Integer> list = IntStream.range(0, 7).boxed()
                .collect(collectingAndThen(toList(), ImmutableList::copyOf));
如果此选项对您来说有点冗长,并且您希望在许多地方使用它,您可以创建自己的收集器:

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(toImmutableList());
List List=IntStream.range(0,7)
.boxed()
.collect(toImmutableList());

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

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

.

仅供参考,在没有Java 8的情况下,在番石榴中有一种合理的方法可以做到这一点:

ImmutableSortedSet<Integer> set = ContiguousSet.create(
    Range.closedOpen(0, 7), DiscreteDomain.integers());
ImmutableList<Integer> list = set.asList();
ImmutableSortedSet集=ContiguousSet.create(
Range.closedOpen(0,7),离散域整数();
ImmutableList=set.asList();
如果您实际上不需要
列表
语义,只需要使用
导航集
,那就更好了,因为
连续集
不需要实际存储其中的所有元素(只需要
范围
离散域
亚历克西斯公认答案中的方法现在包含在中,可用作:

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

编辑:
ImmutableList.toImmutableList
中删除了
@Beta
,以及()中的其他常用API。

顺便说一句:自JDK 10以来,它可以在纯Java中完成:

List<Integer> list = IntStream.range(0, 7)
    .collect(Collectors.toUnmodifiableList());
List List=IntStream.range(0,7)
.collect(Collectors.toUnmodifiableList());
此外,还提供了
toUnmodifiableSet
toUnmodifiableMap


在收集器内部,它是通过List.of(List.toArray())完成的。

这仍然会创建一个中间列表,不是吗?我想避免这种情况。
ImmutableList.Builder
有什么帮助吗?@zoltan您可以直接在生成器中累积值(请参见编辑),然后调用
build()
。感谢您提供的详细答案。这似乎是目前正在解决的问题:,这里还有一个很好的例子(很像你所建议的):@Zoltan啊,是的;好发现;它只是将第二个备选方案包装成实用方法。比定义自己的
收集器
类要好一点:-)引用类型可以是
不可变列表
(而不是
列表
)。方法标记为@Beta。因此,从Guava 26.0开始,docs就不再推荐Gmail了?仍然是
@Beta
。从长远来看,谷歌在2004年至2009年间一直将Gmail置于Beta标签之下,这在2004年发布时已经是一款相当稳定、成熟的产品。一般来说,谷歌很不愿意推广Beta版的产品。几乎到了喜剧的程度。这并不完全正确,因为
ImmutableCollections.List12
ImmutableCollections.ListN
!=番石榴的
不可变列表
。从实际的角度来看,你基本上是正确的,但在你的回答中提到这一细微差别还是有意义的。
Stream<Integer> stream = IntStream.range(0, 7).boxed();
List<Integer> list = ImmutableList.copyOf(stream.iterator());
ImmutableSortedSet<Integer> set = ContiguousSet.create(
    Range.closedOpen(0, 7), DiscreteDomain.integers());
ImmutableList<Integer> list = set.asList();
ImmutableList<Integer> list = IntStream.range(0, 7)
    .boxed()
    .collect(ImmutableList.toImmutableList());
List<Integer> list = IntStream.range(0, 7)
    .collect(Collectors.toUnmodifiableList());