Java 8 Collectors.toMap SortedMap

Rob*_*ain 64 java lambda java-8 java-stream collectors

我正在使用Java 8 lambdas并希望Collectors toMap用来返回一个SortedMap.我能想出的最好的是调用下面Collectors toMap用假设法mergeFunctionmapSupplier等于TreeMap::new.

public static <T, K, U, M extends Map<K, U>>
        Collector<T, ?, M> toMap(Function<? super T, ? extends K> keyMapper,
                Function<? super T, ? extends U> valueMapper,
                BinaryOperator<U> mergeFunction,
                Supplier<M> mapSupplier) {
    BiConsumer<M, T> accumulator = (map, element) -> map.merge(keyMapper.apply(element),
            valueMapper.apply(element), mergeFunction);
    return new CollectorImpl<>(mapSupplier, accumulator, mapMerger(mergeFunction), CH_ID);
}
Run Code Online (Sandbox Code Playgroud)

我不想传递合并函数,正如我想要throwingMerger()的那样,与基本toMap实现相同,如下所示:

public static <T, K, U>
        Collector<T, ?, Map<K, U>> toMap(Function<? super T, ? extends K> keyMapper,
                Function<? super T, ? extends U> valueMapper) {
    return toMap(keyMapper, valueMapper, throwingMerger(), HashMap::new);
}
Run Code Online (Sandbox Code Playgroud)

什么是使用Collectors返回的最佳实践方法SortedMap

dka*_*zel 70

我认为你不能比这更好:

.collect(Collectors.toMap(keyMapper, valueMapper,
                        (v1,v2) ->{ throw new RuntimeException(String.format("Duplicate key for values %s and %s", v1, v2));},
                        TreeMap::new));
Run Code Online (Sandbox Code Playgroud)

其中throwlambda是相同的,throwingMerger()但我不能直接调用它,因为它的包是私有的(你当然总是可以为它创建自己的静态方法throwingMerger().)

  • 您指定为"k"的参数不是*key*,正如字母所暗示的那样,而是用于合并的二进制操作的第一个值. (4认同)
  • 我从`(k,v)`变为`(v1,v2)`,因为lambda参数实际上是两个冲突的值.JDK中的`throwingMerger()`是错误的.我希望你不介意.:) (3认同)
  • 是的,异常消息很糟糕.http://mail.openjdk.java.net/pipermail/lambda-dev/2014-April/012005.html (2认同)
  • 这个 SO-answer:http://stackoverflow.com/questions/25712591/java8-convert-one-map-to-an-another-using-stream 建议了一种更短的方法来解决这个问题,只需假设没有重复(如果有)。 (2认同)

Rob*_*ain 8

根据dkatzel确认没有一个很好的API方法,我选择维护我自己的自定义Collectors类:

public final class StackOverflowExampleCollectors {

    private StackOverflowExampleCollectors() {
        throw new UnsupportedOperationException();
    }

    private static <T> BinaryOperator<T> throwingMerger() {
        return (u, v) -> {
            throw new IllegalStateException(String.format("Duplicate key %s", u));
        };
    }

    public static <T, K, U, M extends Map<K, U>> Collector<T, ?, M> toMap(Function<? super T, ? extends K> keyMapper,
            Function<? super T, ? extends U> valueMapper, Supplier<M> mapSupplier) {
        return Collectors.toMap(keyMapper, valueMapper, throwingMerger(), mapSupplier);
    }

}
Run Code Online (Sandbox Code Playgroud)

  • 您应该更改异常消息。您使用其中一个值(正如 JDK 所做的那样:https://bugs.openjdk.java.net/browse/JDK-8040892),但消息表明它是关键。可以显示密钥(http://hg.openjdk.java.net/jdk9/dev/jdk/rev/8b80651ce43f),但这更复杂,所以也许只使用` throw new IllegalStateException(String.format("值 %s 和 %s"、u、v));` 的键重复。 (2认同)

Tag*_*eev 7

似乎在没有定义自己的throwingMerger()方法或使用显式lambda的情况下,没有标准的方法可以做到这一点.在我的StreamEx库中,我定义了toSortedMap使用我自己的方法throwingMerger().

  • 这看起来像一个疏忽,没有一个方法签名在那里需要一个地图供应商. (4认同)

Dan*_*iel 5

执行此操作的另一种方法是允许Collectors.toMap()返回将要返回的任何地图,然后将其传递给新的TreeMap <>()。

需要注意的是,这仅在您的“ hashCode()+ equals()”和“ compareTo”一致时才有效。如果不一致,那么HashMap最终将删除与TreeMap不同的键集。


uwe*_*uwe 5

如果您使用番石榴库,那么您可以使用:

.collect(ImmutableSortedMap.toImmutableSortedMap(comparator, keyMapper, valueMapper));
Run Code Online (Sandbox Code Playgroud)

生成的映射将是 aSortedMap并且也是不可变的。