Me gustaría hacer lo siguiente:
List<Integer> list = IntStream.range(0, 7).collect(Collectors.toList());
pero de una manera que la lista resultante es una implementación de la de Guava ImmutableList
.
Sé que podría hacer
List<Integer> list = IntStream.range(0, 7).collect(Collectors.toList());
List<Integer> immutableList = ImmutableList.copyOf(list);
pero me gustaría cobrarle directamente. He intentado
List<Integer> list = IntStream.range(0, 7)
.collect(Collectors.toCollection(ImmutableList::of));
pero arrojó una excepción:
java.lang.UnsupportedOperationException en com.google.common.collect.ImmutableCollection.add (ImmutableCollection.java:96)
java-8
guava
java-stream
Zoltán
fuente
fuente
@Beta
partir de Guayaba 26.0.Aquí es donde el
collectingAndThen
colector es útil:List<Integer> list = IntStream.range(0, 7).boxed() .collect(collectingAndThen(toList(), ImmutableList::copyOf));
Aplica la transformación a la
List
que acaba de construir; resultando en unImmutableList
.O puede cobrar directamente en el
Builder
y llamarbuild()
al final:List<Integer> list = IntStream.range(0, 7) .collect(Builder<Integer>::new, Builder<Integer>::add, (builder1, builder2) -> builder1.addAll(builder2.build())) .build();
Si esta opción es un poco detallada para usted y desea usarla en muchos lugares, puede crear su propio recopilador:
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(); } }
y entonces:
List<Integer> list = IntStream.range(0, 7) .boxed() .collect(new ImmutableListCollector<>());
En caso de que el enlace desaparezca en los comentarios; mi segundo enfoque podría definirse en un método de utilidad estática que simplemente usa
Collector.of
. Es más sencillo que crear tu propiaCollector
clase.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); }
y el uso:
List<Integer> list = IntStream.range(0, 7) .boxed() .collect(toImmutableList());
fuente
ImmutableList.Builder
ser de alguna ayuda?build()
.Collector
clase :-)ImmutableList<Integer>
(en lugar deList<Integer>
).Si bien no es una respuesta directa a mi pregunta (no usa colectores), este es un enfoque bastante elegante que no usa colecciones intermedias:
Stream<Integer> stream = IntStream.range(0, 7).boxed(); List<Integer> list = ImmutableList.copyOf(stream.iterator());
Fuente .
fuente
Por cierto: desde JDK 10 se puede hacer en Java puro:
List<Integer> list = IntStream.range(0, 7) .collect(Collectors.toUnmodifiableList());
También
toUnmodifiableSet
ytoUnmodifiableMap
disponible.Dentro del colector se hizo a través de
List.of(list.toArray())
fuente
ImmutableCollections.List12
yImmutableCollections.ListN
! = GuayabaImmutableList
. Desde una perspectiva práctica, en su mayoría tiene razón, pero aún tendría sentido mencionar este matiz en su respuesta.Para su información, hay una forma razonable de hacer esto en Guava sin Java 8:
ImmutableSortedSet<Integer> set = ContiguousSet.create( Range.closedOpen(0, 7), DiscreteDomain.integers()); ImmutableList<Integer> list = set.asList();
Si en realidad no necesita la
List
semántica y solo puede usar aNavigableSet
, eso es aún mejor, yaContiguousSet
que a no tiene que almacenar todos los elementos en él (solo elRange
yDiscreteDomain
).fuente