如何将 Java 8 流收集到 Guava ImmutableCollection 中?
How can I collect a Java 8 stream into a Guava ImmutableCollection?
我想做以下事情:
List<Integer> list = IntStream.range(0, 7).collect(Collectors.toList());
但在某种程度上,结果列表是 Guava 的 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
at com.google.common.collect.ImmutableCollection.add(ImmutableCollection.java:96)
这是 collectingAndThen
收集器有用的地方:
List<Integer> list = IntStream.range(0, 7).boxed()
.collect(collectingAndThen(toList(), ImmutableList::copyOf));
它将转换应用于您刚刚构建的 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();
如果这个选项对您来说有点冗长并且您想在很多地方使用它,您可以创建自己的收集器:
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<>());
以防 link 在评论中消失;我的第二种方法可以在一个只使用 Collector.of
的静态实用程序方法中定义。它比创建您自己的 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);
}
和用法:
List<Integer> list = IntStream.range(0, 7)
.boxed()
.collect(toImmutableList());
虽然不是我的问题的直接答案(它不使用收集器),但这是一种相当优雅的方法,不使用中间集合:
Stream<Integer> stream = IntStream.range(0, 7).boxed();
List<Integer> list = ImmutableList.copyOf(stream.iterator());
仅供参考,在没有 Java 8:
的番石榴中有一种合理的方法可以做到这一点
ImmutableSortedSet<Integer> set = ContiguousSet.create(
Range.closedOpen(0, 7), DiscreteDomain.integers());
ImmutableList<Integer> list = set.asList();
如果您实际上不需要 List
语义并且可以只使用 NavigableSet
,那更好,因为 ContiguousSet
不必实际存储所有元素在其中(只有 Range
和 DiscreteDomain
)。
Alexis 接受的答案中的 toImmutableList()
方法现在包含在 Guava 21 中,可以用作:
ImmutableList<Integer> list = IntStream.range(0, 7)
.boxed()
.collect(ImmutableList.toImmutableList());
编辑: 从 ImmutableList.toImmutableList
中删除 @Beta
以及 Release 27.1 (6242bdd 中的其他常用 API)。
顺便说一句:因为 JDK 10 它可以在纯 Java:
中完成
List<Integer> list = IntStream.range(0, 7)
.collect(Collectors.toUnmodifiableList());
还有 toUnmodifiableSet
和 toUnmodifiableMap
可用。
内部收集器是通过 List.of(list.toArray())
完成的
我想做以下事情:
List<Integer> list = IntStream.range(0, 7).collect(Collectors.toList());
但在某种程度上,结果列表是 Guava 的 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 at com.google.common.collect.ImmutableCollection.add(ImmutableCollection.java:96)
这是 collectingAndThen
收集器有用的地方:
List<Integer> list = IntStream.range(0, 7).boxed()
.collect(collectingAndThen(toList(), ImmutableList::copyOf));
它将转换应用于您刚刚构建的 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();
如果这个选项对您来说有点冗长并且您想在很多地方使用它,您可以创建自己的收集器:
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<>());
以防 link 在评论中消失;我的第二种方法可以在一个只使用 Collector.of
的静态实用程序方法中定义。它比创建您自己的 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);
}
和用法:
List<Integer> list = IntStream.range(0, 7)
.boxed()
.collect(toImmutableList());
虽然不是我的问题的直接答案(它不使用收集器),但这是一种相当优雅的方法,不使用中间集合:
Stream<Integer> stream = IntStream.range(0, 7).boxed();
List<Integer> list = ImmutableList.copyOf(stream.iterator());
仅供参考,在没有 Java 8:
的番石榴中有一种合理的方法可以做到这一点ImmutableSortedSet<Integer> set = ContiguousSet.create(
Range.closedOpen(0, 7), DiscreteDomain.integers());
ImmutableList<Integer> list = set.asList();
如果您实际上不需要 List
语义并且可以只使用 NavigableSet
,那更好,因为 ContiguousSet
不必实际存储所有元素在其中(只有 Range
和 DiscreteDomain
)。
Alexis 接受的答案中的 toImmutableList()
方法现在包含在 Guava 21 中,可以用作:
ImmutableList<Integer> list = IntStream.range(0, 7)
.boxed()
.collect(ImmutableList.toImmutableList());
编辑: 从 ImmutableList.toImmutableList
中删除 @Beta
以及 Release 27.1 (6242bdd 中的其他常用 API)。
顺便说一句:因为 JDK 10 它可以在纯 Java:
中完成List<Integer> list = IntStream.range(0, 7)
.collect(Collectors.toUnmodifiableList());
还有 toUnmodifiableSet
和 toUnmodifiableMap
可用。
内部收集器是通过 List.of(list.toArray())