Ich verwende Java 8-Lambdas und möchte mit Collectors
toMap
eine SortedMap
zurückgeben. Am besten kann ich dazu die folgende Collectors
toMap
-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 toMap
implementation 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?
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.)
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);
}
}
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.
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.
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.