Estoy tratando de implementar un colector simple, que toma una lista de colectores y simultáneamente recopila valores de formas ligeramente diferentes a las de una secuencia.
Es bastante similar a Collectors.teeing
, pero se diferencia en que
La firma de tipo que quiero tener es
public static <T, R> Collector<T, ?, List<R>> list( final List<Collector<T, ?, R>> downstreamCollectors);
Una forma de crear un colector de este tipo sería emparejar recursivamente los colectores en T, así:
public static <T, R> Collector<T, ?, List<R>> list( final List<Collector<T, ?, R>> downstreamCollectors) { return listrec( Collectors.collectingAndThen(downstreamCollectors.get(0), List::of), downstreamCollectors.stream().skip(1).toList()); } private static <T, R> Collector<T, ?, List<R>> listrec( final Collector<T, ?, List<R>> teedCollectors, final List<Collector<T, ?, R>> downstreamCollectors) { if (downstreamCollectors.size() == 0) { return teedCollectors; } else { return listrec( teeing( teedCollectors, downstreamCollectors.get(0), (l, s) -> Stream.concat(l.stream(), Stream.of(s)).toList()), downstreamCollectors.stream().skip(1).toList()); } }
Algo se siente un poco "apagado" con esta solución, así que estoy tratando de crear el colector yo mismo, algo como:
public static <T, R> Collector<T, ?, List<R>> list2( final List<Collector<T, ?, R>> downstreamCollectors) { return Collector.of( () -> downstreamCollectors.stream().map(c -> c.supplier().get()).toList(), (accumulators, t) -> IntStream.range(0, downstreamCollectors.size()) .forEach( i -> downstreamCollectors.get(i).accumulator().accept(accumulators.get(i), t)), (accumulator1, accumulator2) -> IntStream.range(0, downstreamCollectors.size()) .mapToObj( i -> downstreamCollectors .get(i) .combiner() .apply(accumulator1.get(i), accumulator2.get(i))) .toList(), accumulators -> IntStream.range(0, downstreamCollectors.size()) .mapToObj(i -> downstreamCollectors.get(i).finisher().apply(accumulators.get(i))) .toList()); }
Debido al comodín ilimitado en el tipo de acumulador de los recopiladores posteriores, esto no se compila. Cambiando la firma de tipo a
public static <T, A, R> Collector<? super T, ?, List<R>> list2( final List<Collector<? super T, A, R>> downstreamCollectors);
resuelve el problema, pero desafortunadamente hace que el método sea mucho menos útil ya que los recopiladores posteriores (como los recopiladores integrados de java.util.stream.Collectors
) normalmente tendrían un comodín ilimitado en el tipo de acumulador.
¿Hay otra forma de implementar esto, manteniendo el comodín en la firma del método?
Estoy usando OpenJDK 17.0.2.