Je voudrais faire ce qui suit:
List<Integer> list = IntStream.range(0, 7).collect(Collectors.toList());
mais d'une manière que la liste résultante est une implémentation de ImmutableList
de Guava.
Je sais que je pourrais faire
List<Integer> list = IntStream.range(0, 7).collect(Collectors.toList());
List<Integer> immutableList = ImmutableList.copyOf(list);
mais je voudrais y recueillir directement. J'ai essayé
List<Integer> list = IntStream.range(0, 7)
.collect(Collectors.toCollection(ImmutableList::of));
mais il a jeté une exception:
Java.lang.UnsupportedOperationException sur com.google.common.collect.ImmutableCollection.add (ImmutableCollection.Java:96)
La méthode toImmutableList()
dans la réponse acceptée d'Alexis est maintenant incluse dans Guava 21 et peut être utilisée comme:
ImmutableList<Integer> list = IntStream.range(0, 7)
.boxed()
.collect(ImmutableList.toImmutableList());
C'est là que le collecteur collectingAndThen
est utile:
List<Integer> list = IntStream.range(0, 7).boxed()
.collect(collectingAndThen(toList(), ImmutableList::copyOf));
Il applique la transformation au List
que vous venez de construire; résultant en un ImmutableList
.
Ou vous pouvez collecter directement dans le Builder
et appeler build()
à la fin:
List<Integer> list = IntStream.range(0, 7)
.collect(Builder<Integer>::new, Builder<Integer>::add, (builder1, builder2) -> builder1.addAll(builder2.build()))
.build();
Si cette option est un peu bavarde pour vous et que vous souhaitez l'utiliser à de nombreux endroits, vous pouvez créer votre propre collecteur:
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();
}
}
et alors:
List<Integer> list = IntStream.range(0, 7)
.boxed()
.collect(new ImmutableListCollector<>());
Juste au cas où le lien disparaît dans les commentaires; ma deuxième approche pourrait être définie dans une méthode utilitaire statique qui utilise simplement Collector.of
. C'est plus simple que de créer votre propre classe 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);
}
et l'utilisation:
List<Integer> list = IntStream.range(0, 7)
.boxed()
.collect(toImmutableList());
Bien que ce ne soit pas une réponse directe à ma question (il n'utilise pas de collectionneurs), c'est une approche assez élégante qui n'utilise pas de collections intermédiaires:
Stream<Integer> stream = IntStream.range(0, 7).boxed();
List<Integer> list = ImmutableList.copyOf(stream.iterator());
Source .
BTW: depuis JDK 10 cela peut se faire en Java pur:
List<Integer> list = IntStream.range(0, 7)
.collect(Collectors.toUnmodifiableList());
toUnmodifiableSet
et toUnmodifiableMap
sont également disponibles.
Dans le collecteur, cela a été fait via List.of(list.toArray())
Pour info, il existe un moyen raisonnable de le faire en goyave sans Java 8:
ImmutableSortedSet<Integer> set = ContiguousSet.create(
Range.closedOpen(0, 7), DiscreteDomain.integers());
ImmutableList<Integer> list = set.asList();
Si vous n'avez pas réellement besoin de la sémantique List
et que vous pouvez simplement utiliser un NavigableSet
, c'est encore mieux puisqu'un ContiguousSet
n'a pas besoin de stocker réellement tous les éléments qu'il contient (juste le Range
et DiscreteDomain
).