it-swarm.com.de

Java 8 Collectors.toMap SortedMap

Ich verwende Java 8-Lambdas und möchte mit CollectorstoMap eine SortedMap zurückgeben. Am besten kann ich dazu die folgende CollectorstoMap-Methode aufrufen, deren Dummy mergeFunction und mapSupplier gleich TreeMap::new sind.

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

Ich möchte jedoch keine Merge-Funktion übergeben, da ich nur throwingMerger() auf dieselbe Weise wie die grundlegende toMapimplementation wie folgt verwenden möchte:

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

Was wäre die beste Methode, um mit Collectors eine SortedMap zurückzugeben?

56
Robert Bain

Ich glaube nicht, dass du viel besser bekommen kannst als das:

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

wobei throw lambda dasselbe ist wie throwingMerger(), aber ich kann das nicht direkt aufrufen, da es das Paket privat ist (Sie können natürlich immer eine eigene statische Methode dafür erstellen, wie throwingMerger() ist.)

54
dkatzel

Basierend auf der Bestätigung von dkatzel, dass es keine Nice-API-Methode gibt, habe ich mich für die Pflege meiner eigenen benutzerdefinierten Collectors-Klasse entschieden:

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

Es scheint, dass es keine Standardmethode gibt, dies zu tun, ohne Ihre eigene throwingMerger() Methode zu definieren oder explizites Lambda zu verwenden. In meiner StreamEx-Bibliothek habe ich die Methode toSortedMap definiert, die auch verwendet meine eigene throwingMerger() verwendet.

7
Tagir Valeev

Sie können dies auch tun, indem Sie Collectors.toMap () die zurückgegebene Map zurückgeben lassen und diese dann an eine neue TreeMap <> () übergeben.

Der Nachteil dabei ist, dass dies nur funktioniert, wenn "hashCode () + equals ()" und "compareTo" konsistent sind. Wenn sie nicht konsistent sind, wird die HashMap am Ende einen anderen Schlüsselsatz als Ihre TreeMap entfernen.

4
Daniel

Wenn Sie die Guava-Bibliothek verwenden, können Sie Folgendes verwenden:

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

Die resultierende Karte ist eine SortedMap und auch unveränderlich. 

0
uwe