Eu gostaria de fazer o seguinte:
List<Integer> list = IntStream.range(0, 7).collect(Collectors.toList());
mas de uma forma que a lista resultante é uma implementação da Goiaba ImmutableList
.
Eu sei que poderia fazer
List<Integer> list = IntStream.range(0, 7).collect(Collectors.toList());
List<Integer> immutableList = ImmutableList.copyOf(list);
mas eu gostaria de cobrar diretamente. eu tentei
List<Integer> list = IntStream.range(0, 7)
.collect(Collectors.toCollection(ImmutableList::of));
mas lançou uma exceção:
java.lang.UnsupportedOperationException em com.google.common.collect.ImmutableCollection.add (ImmutableCollection.java:96)
java-8
guava
java-stream
Zoltán
fonte
fonte
@Beta
em goiaba 26.0.É aqui que o
collectingAndThen
coletor é útil:List<Integer> list = IntStream.range(0, 7).boxed() .collect(collectingAndThen(toList(), ImmutableList::copyOf));
Ele aplica a transformação ao que
List
você acabou de construir; resultando em umImmutableList
.Ou você pode cobrar diretamente no
Builder
e ligarbuild()
no final:List<Integer> list = IntStream.range(0, 7) .collect(Builder<Integer>::new, Builder<Integer>::add, (builder1, builder2) -> builder1.addAll(builder2.build())) .build();
Se esta opção for um pouco prolixa para você e quiser usá-la em muitos lugares, você pode criar seu próprio coletor:
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(); } }
e depois:
List<Integer> list = IntStream.range(0, 7) .boxed() .collect(new ImmutableListCollector<>());
Para o caso de o link desaparecer nos comentários; minha segunda abordagem poderia ser definida em um método utilitário estático que simplesmente usa
Collector.of
. É mais simples do que criar sua própriaCollector
classe.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); }
e o uso:
List<Integer> list = IntStream.range(0, 7) .boxed() .collect(toImmutableList());
fonte
ImmutableList.Builder
ser de alguma ajuda?build()
.Collector
classe :-)ImmutableList<Integer>
(em vez deList<Integer>
).Embora não seja uma resposta direta à minha pergunta (não usa coletores), esta é uma abordagem bastante elegante que não usa coleções intermediárias:
Stream<Integer> stream = IntStream.range(0, 7).boxed(); List<Integer> list = ImmutableList.copyOf(stream.iterator());
Fonte .
fonte
BTW: desde o JDK 10, isso pode ser feito em Java puro:
List<Integer> list = IntStream.range(0, 7) .collect(Collectors.toUnmodifiableList());
Também
toUnmodifiableSet
etoUnmodifiableMap
disponíveis.No coletor interno foi feito via
List.of(list.toArray())
fonte
ImmutableCollections.List12
eImmutableCollections.ListN
! = GoiabaImmutableList
. De uma perspectiva prática, você está correto, mas ainda faria sentido mencionar essa nuance em sua resposta.Para sua informação, há uma maneira razoável de fazer isso no Guava sem Java 8:
ImmutableSortedSet<Integer> set = ContiguousSet.create( Range.closedOpen(0, 7), DiscreteDomain.integers()); ImmutableList<Integer> list = set.asList();
Se você realmente não precisa da
List
semântica e pode apenas usar umNavigableSet
, isso é ainda melhor, jáContiguousSet
que a não precisa realmente armazenar todos os elementos nele (apenas oRange
eDiscreteDomain
).fonte