web-dev-qa-db-ja.com

Java 8 Collectors.toMap SortedMap

私はJava 8ラムダを使用しており、CollectorstoMapを使用してSortedMapを返すことを望んでいます。ダミーのCollectorstoMapが_TreeMap::new_に等しい以下のmergeFunctionmapSupplierメソッドを呼び出します。

_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);
}
_

ただし、次の基本的なtoMapimplementationと同じように、throwingMerger()が必要なだけなので、マージ関数を渡したくありません。

_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);
}
_

Collectorsを使用してSortedMapを返すベストプラクティスの方法は何でしょうか。

63
Robert Bain

これよりずっと良くなるとは思わない:

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

throwラムダはthrowingMerger()と同じですが、パッケージプライベートなので直接呼び出すことはできません(もちろん、throwingMerger()です。

67
dkatzel

Nice APIメソッドがないというdkatzelの確認に基づいて、私は独自のカスタムコレクタークラスを維持することを選択しました。

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);
    }

}
8
Robert Bain

独自のthrowingMerger()メソッドを定義したり、明示的なラムダを使用せずにこれを行う標準的な方法はないようです。 StreamExライブラリで toSortedMap メソッドを定義しました。これは ses 自分のthrowingMerger()でもあります。

7
Tagir Valeev

これを行うもう1つの方法は、Collectors.toMap()が返すマップを返すことを許可し、それを新しいTreeMap <>()に渡すことです。

ここでの注意点は、「hashCode()+ equals()」と「compareTo」が一貫している場合にのみ機能するということです。それらが一貫していない場合は、HashMapがTreeMapとは異なるキーのセットを削除することになります。

5
Daniel

Guavaライブラリを使用する場合は、次を使用できます。

.collect(ImmutableSortedMap.toImmutableSortedMap(comparator, keyMapper, valueMapper));

結果のマップはSortedMapであり、不変です。

1
uwe