Collectors.converting
Peter Levart
peter.levart at gmail.com
Wed Jan 30 08:22:34 UTC 2019
On 1/29/19 9:52 PM, Brian Goetz wrote:
> How is this different from Collectors.collectingAndThen?
Hi Brian,
It is exactly the same!
I'm sorry, I haven discovered that method when I needed it. Perhaps I
was looking for another name?
Regards, Peter
>
> On 1/29/2019 3:30 PM, Peter Levart wrote:
>> Hi,
>>
>> I wonder if there's any interest in adding a convenience factory
>> method for a Collector to the standard repertoire which would look
>> like the following:
>>
>> /**
>> * Convert given {@link Collector} so that it applies an
>> additional finisher function that
>> * converts the result of given collector. The characteristics of
>> returned collector is
>> * the same as that of the given inner collector but without any
>> * {@link
>> java.util.stream.Collector.Characteristics#IDENTITY_FINISH}.
>> *
>> * @param collector the inner collector to delegate
>> collection to
>> * @param resultConverter the additional result finisher function
>> * @param <T> the type of input stream elements
>> * @param <A> the type of intermediate aggregation
>> * @param <R> the type of result of inner collector
>> * @param <RR> the type of final result
>> * @return the converted collector
>> */
>> public static <T, A, R, RR> Collector<T, A, RR> converting(
>> Collector<T, A, R> collector,
>> Function<? super R, RR> resultConverter
>> ) {
>> return new Collector<T, A, RR>() {
>> @Override
>> public Supplier<A> supplier() { return
>> collector.supplier(); }
>>
>> @Override
>> public BiConsumer<A, T> accumulator() { return
>> collector.accumulator(); }
>>
>> @Override
>> public BinaryOperator<A> combiner() { return
>> collector.combiner(); }
>>
>> @Override
>> public Function<A, RR> finisher() { return
>> resultConverter.compose(collector.finisher()); }
>>
>> @Override
>> public Set<Characteristics> characteristics() {
>> EnumSet<Characteristics> characteristics =
>> EnumSet.noneOf(Characteristics.class);
>> characteristics.addAll(collector.characteristics());
>> characteristics.remove(Characteristics.IDENTITY_FINISH);
>> return Collections.unmodifiableSet(characteristics);
>> }
>> };
>> }
>>
>>
>> The rationale is as follows... Composability of collectors allows
>> doing things like:
>>
>> interface Measurement {
>> long value();
>> String type();
>> }
>>
>> Stream<Measurement> measurements = ....
>>
>> Map<String, LongSummaryStatistics> statsByType =
>> measurements
>> .collect(
>> groupingBy(
>> Measurement::type,
>> summarizingLong(Measurement::value)
>> )
>> );
>>
>> ...but say I wanted the final result to be a map of avarage values by
>> type and the values to be BigDecimal objects calculated with scale of
>> 19. I can create an intermediate map like above and then transform it
>> to new map, like this:
>>
>> static BigDecimal toBDAverage(LongSummaryStatistics stats) {
>> return BigDecimal.valueOf(stats.getSum())
>> .divide(
>> BigDecimal.valueOf(stats.getCount()),
>> 20, RoundingMode.HALF_EVEN);
>> }
>>
>> Map<String, BigDecimal> averageByType =
>> statsByType
>> .entrySet()
>> .stream()
>> .collect(toMap(Map.Entry::getKey, e ->
>> toBDAverage(e.getValue())));
>>
>> ...this is ugly as it requires intermediate result to be materialized
>> as a HashMap. Wouldn't it be possible to collect the original stream
>> to final result in one go?
>>
>> With the above Collectors.converting factory method, it would:
>>
>> Map<String, BigDecimal> averageByType =
>> measurements
>> .collect(
>> groupingBy(
>> Measurement::type,
>> converting(
>> summarizingLong(Measurement::value),
>> stats -> toBDAverage(stats)
>> )
>> )
>> );
>>
>> We already have Collectors.mapping(Function, Collector) method that
>> constructs Collector that maps elements to be collected by inner
>> collector. Collectors.converting(Collectors, Function) would be a
>> twin brother that constructs Collector that converts the collection
>> result of the inner collector. Both are useful in compositions like
>> above, but we only have the 1st...
>>
>> What do you think?
>>
>> Regards, Peter
>>
>
More information about the core-libs-dev
mailing list