Java 8 Collectors.toMap SortedMap

Lesezeit: 4 Minuten

Benutzer-Avatar
Robert Bain

Ich verwende Java 8-Lambdas und möchte verwenden Collectors toMap zurückgeben a SortedMap. Das Beste, was mir einfällt, ist, Folgendes anzurufen Collectors toMap Methode mit einem Dummy mergeFunction und mapSupplier gleicht 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);
}

Ich möchte jedoch keine Zusammenführungsfunktion übergeben, da ich nur möchte throwingMerger()auf die gleiche Weise wie die Basis toMapUmsetzung wie folgt:

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 Best-Practice-Methode zur Verwendung Collectors zurückgeben a SortedMap?

Benutzer-Avatar
dkatzel

Ich denke viel besser geht es nicht:

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

bei dem die throw Lambda ist das gleiche wie throwingMerger() aber ich kann das nicht direkt aufrufen, da es sich um ein privates Paket handelt (Sie können natürlich immer Ihre eigene statische Methode dafür erstellen, wie z throwingMerger() ist. )

  • Der von Ihnen festgelegte Parameter k ist nicht der Schlüsselwie der Buchstabe andeuten würde, sondern der erste Wert der binären Operation zum Zusammenführen.

    – Antak

    25. September 2015 um 5:17 Uhr

  • @antak das Javadoc ist verwirrend. Aber ich nahm tatsächlich die Ausnahmemeldung ab Sammler#throwingMerger das sagt “duplicate key” für den ersten Parameter

    – dkatzel

    25. September 2015 um 14:53 Uhr


  • Ja, die Ausnahmemeldung ist schlecht. mail.openjdk.java.net/pipermail/lambda-dev/2014-April/…

    – Antak

    26. September 2015 um 8:07 Uhr

  • Diese SO-Antwort: stackoverflow.com/questions/25712591/… schlägt einen kürzeren Weg vor, um dies auszudrücken, indem einfach angenommen wird, dass keine Duplikate vorhanden sind (überschreiben, falls vorhanden).

    – mortensi

    3. Mai 2016 um 11:12 Uhr


  • Ich wechselte von (k,v) zu (v1,v2), da die Lambda-Parameter tatsächlich die beiden widersprüchlichen Werte sind. Das throwingMerger() im JDK ist falsch. Ich hoffe, Sie haben nichts dagegen. 🙂

    – Christoffer Hammarström

    8. Dezember 2016 um 19:14 Uhr

Benutzer-Avatar
Robert Bain

Basierend auf der Bestätigung von dkatzel, dass es keine nette API-Methode gibt, habe ich mich dafür entschieden, meine eigene benutzerdefinierte Collectors-Klasse beizubehalten:

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

}

  • Sie sollten die Ausnahmemeldung ändern. Sie verwenden einen der Werte (wie es das JDK getan hat: bugs.openjdk.java.net/browse/JDK-8040892), aber die Meldung deutet darauf hin, dass es sich um den Schlüssel handelt. Es ist möglich, den Schlüssel anzuzeigen (hg.openjdk.java.net/jdk9/dev/jdk/rev/8b80651ce43f), aber das ist komplexer, also vielleicht einfach verwenden throw new IllegalStateException(String.format("Duplicate key for values %s and %s", u, v));.

    – Martin

    7. November 2017 um 16:14 Uhr


  • Hey @Martin, danke für die Links! In dem Beispiel habe ich versucht, den Code wörtlich aus dem Privaten zu posten throwingMerger Methode der Collectors Klasse, um zu zeigen, dass ich die Tatsache umgangen habe, dass es privat ist. Ich verstehe vollkommen, woher Sie kommen, und die Fehlermeldung, die Sie präsentieren, ist besser, lenkt aber vielleicht davon ab, zu sagen: “Machen Sie genau das Gleiche, der Sichtbarkeitsmodifikator kommt in die Quere”? Wie wäre es, wenn ich Ihren Vorschlag unten als Bearbeitung hinzufüge und Ihre Quellen zitiere?

    – Robert Bain

    7. November 2017 um 22:44 Uhr

Scheint, dass es keinen Standardweg gibt, dies zu tun, ohne einen eigenen zu definieren throwingMerger() -Methode oder mit explizitem Lambda. In meiner StreamEx-Bibliothek habe ich die toSortedMap Methode, die auch Verwendet mein eigenes throwingMerger().

  • Es scheint ein Versehen zu sein, keine Methodensignatur zu haben, die einen Kartenlieferanten benötigt.

    – Robert Bain

    23. Juni 2015 um 16:41 Uhr

Sie können dies auch tun, indem Sie Collectors.toMap() erlauben, die zurückzugebende Karte zurückzugeben, und diese dann an eine neue TreeMap<>() übergeben.

Der Vorbehalt dabei ist, dass dies nur funktioniert, wenn Ihr “hashCode()+equals()” und “compareTo” konsistent sind. Wenn sie nicht konsistent sind, wird die HashMap am Ende andere Schlüsselsätze entfernen als Ihre TreeMap.

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

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

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

1215840cookie-checkJava 8 Collectors.toMap SortedMap

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy