How to force max to return ALL maximum values in a Java Stream?

后端 未结 7 864
陌清茗
陌清茗 2020-11-22 09:47

I\'ve tested a bit the max function on Java 8 lambdas and streams, and it seems that in case max is executed, even if more than one object compares

相关标签:
7条回答
  • 2020-11-22 10:14

    I implemented more generic collector solution with custom downstream collector. Probably some readers might find it useful:

    public static <T, A, D> Collector<T, ?, D> maxAll(Comparator<? super T> comparator, 
                                                      Collector<? super T, A, D> downstream) {
        Supplier<A> downstreamSupplier = downstream.supplier();
        BiConsumer<A, ? super T> downstreamAccumulator = downstream.accumulator();
        BinaryOperator<A> downstreamCombiner = downstream.combiner();
        class Container {
            A acc;
            T obj;
            boolean hasAny;
            
            Container(A acc) {
                this.acc = acc;
            }
        }
        Supplier<Container> supplier = () -> new Container(downstreamSupplier.get());
        BiConsumer<Container, T> accumulator = (acc, t) -> {
            if(!acc.hasAny) {
                downstreamAccumulator.accept(acc.acc, t);
                acc.obj = t;
                acc.hasAny = true;
            } else {
                int cmp = comparator.compare(t, acc.obj);
                if (cmp > 0) {
                    acc.acc = downstreamSupplier.get();
                    acc.obj = t;
                }
                if (cmp >= 0)
                    downstreamAccumulator.accept(acc.acc, t);
            }
        };
        BinaryOperator<Container> combiner = (acc1, acc2) -> {
            if (!acc2.hasAny) {
                return acc1;
            }
            if (!acc1.hasAny) {
                return acc2;
            }
            int cmp = comparator.compare(acc1.obj, acc2.obj);
            if (cmp > 0) {
                return acc1;
            }
            if (cmp < 0) {
                return acc2;
            }
            acc1.acc = downstreamCombiner.apply(acc1.acc, acc2.acc);
            return acc1;
        };
        Function<Container, D> finisher = acc -> downstream.finisher().apply(acc.acc);
        return Collector.of(supplier, accumulator, combiner, finisher);
    }
    

    So by default it can be collected to a list using:

    public static <T> Collector<T, ?, List<T>> maxAll(Comparator<? super T> comparator) {
        return maxAll(comparator, Collectors.toList());
    }
    

    But you can use other downstream collectors as well:

    public static String joinLongestStrings(Collection<String> input) {
        return input.stream().collect(
                maxAll(Comparator.comparingInt(String::length), Collectors.joining(","))));
    }
    
    0 讨论(0)
提交回复
热议问题