java-8 - descargar - java 8 update 171
¿Cómo puedo recopilar una secuencia de Java 8 en una colección immutable de guayaba? (5)
Me gustaría hacer lo siguiente:
List<Integer> list = IntStream.range(0, 7).collect(Collectors.toList());
pero de alguna manera la lista resultante es una implementación de la Lista
ImmutableList
de Guava.
Se que podria 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)
Aquí es donde el
collectingAndThen
collectAndThen 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 una
ImmutableList
.
O puede recopilar directamente en el
Builder
y llamar a
build()
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<>());
Por si acaso el enlace desaparece 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 simple que crear tu propia clase de
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);
}
y el uso:
List<Integer> list = IntStream.range(0, 7)
.boxed()
.collect(toImmutableList());
El método
toImmutableList()
en la respuesta aceptada de Alexis ahora se incluye en
Guava 21
y se puede usar como:
ImmutableList<Integer> list = IntStream.range(0, 7)
.boxed()
.collect(ImmutableList.toImmutableList());
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 realmente no necesita la semántica de la
List
y solo puede usar un
NavigableSet
, eso es aún mejor ya que un
ContiguousSet
no tiene que almacenar todos los elementos (solo el
Range
y el
DiscreteDomain
).
Por cierto: desde JDK 10 se puede hacer en Java puro:
List<Integer> list = IntStream.range(0, 7)
.collect(Collectors.toUnmodifiableList());
También disponible
toUnmodifiableSet
y
toUnmodifiableMap
.
El recopilador interno se realizó a través de
List.of(list.toArray())
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());