2015-06-23 9 views
47

Ich verwende Java 8 lambdas und möchte CollectorstoMap verwenden, um eine SortedMap zurückzugeben. Das Beste, was ich mir vorstellen kann, ist das folgende CollectorstoMap Verfahren mit einem Dummy mergeFunction und mapSupplier gleich TreeMap::new.Java 8 Collectors.toMap SortedMap

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 will nicht, obwohl in einem Merge-Funktion übergeben, wie ich in der gleichen Art und Weise wie die Grund toMap Implementierung nur throwingMerger() wollen, 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 das Beste wäre, Übung Methode der Verwendung Collectors, um eine SortedMap zurückgeben?

Antwort

35

Ich glaube nicht, Sie als dies viel besser werden:

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

wo das throw Lambda gleich wie throwingMerger() ist, aber ich, dass nicht direkt anrufen kann, da ist es Paket privat (können Sie natürlich immer machen Sie Ihre eigene statische Methode für das wie throwingMerger() ist)

+0

Ich habe * genau * das. –

+0

Ich gehe auf die Custom Collectors Route, da ich ähnliche Dinge in Zukunft sehen kann. –

+4

Der von Ihnen angegebene Parameter 'k' ist nicht der * Schlüssel *, wie der Buchstabe implizieren würde, sondern der erste Wert der binären Operation zum Zusammenführen. – antak

8

Basierend auf Bestätigung des dkatzel, dass es nicht eine schöne API-Methode, ich habe meine eigene benutzerdefinierte Collectors Klasse entschied sich für die Aufrechterhaltung:.

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

} 
+0

Sie sollten die Ausnahmebedingungsnachricht ändern. Sie verwenden einen der Werte (wie das JDK tat: https://bugs.openjdk.java.net/browse/JDK-8040892), aber die Nachricht schlägt vor, dass es der Schlüssel ist. Es ist möglich, den Schlüssel anzuzeigen (http://hg.openjdk.java.net/jdk9/dev/jdk/rev/8b80651ce43f), aber das ist komplexer, also benutze einfach 'throw new IllegalStateException (String.format (" Duplicate key für Werte% s und% s ", u, v));' . – Martin

+0

Hey @Martin, danke für die Links! Im Beispiel habe ich versucht, den Code wörtlich aus der privaten Methode 'throwingMerger' der Klasse' Collectors' zu posten, um zu zeigen, dass ich an der Tatsache arbeitete, dass sie privat ist. Ich sehe total, woher du kommst, und die Fehlermeldung, die du präsentierst, ist besser, aber vielleicht mindert es den Versuch zu sagen: "Tue genau das gleiche, der Sichtbarkeitsmodifikator kommt rein"? Wie wäre es, wenn ich deinen Vorschlag als Bearbeitung unten anfüge und deine Quellen zitierst? –

7

Scheint, dass es keinen Standard Weg gibt, dies zu tun, ohne Ihre eigene throwingMerger() Methode zu definieren oder explizites Lambda zu verwenden. In meiner StreamEx-Bibliothek habe ich die toSortedMap Methode definiert, die auch uses meine eigene throwingMerger() ist.

+4

Es scheint ein Versehen zu sein, da es dort keine Methodensignatur gibt, die einen Kartenlieferanten braucht. –

3

Sie können Collectors.toMap() auch verwenden, um die Map zurückzugeben, die zurückgegeben werden soll, und dann an eine neue TreeMap übergeben (<>()).

Der Vorbehalt ist, dass dies funktioniert nur, wenn Ihre "hashCode() + equals()" und "compareTo" konsistent sind. Wenn sie nicht konsistent sind, endet die HashMap mit dem Entfernen anderer Schlüssel als Ihre TreeMap.