web-dev-qa-db-fra.com

Java 8 Collectors.toMap SortedMap

J'utilise Java 8 lambdas et souhaite utiliser CollectorstoMap pour renvoyer un SortedMap. Le mieux que je puisse trouver est d’appeler la méthode CollectorstoMap suivante avec une variable factice mergeFunction et mapSupplier égale à 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);
}

Cependant, je ne souhaite pas transmettre de fonction de fusion, car je ne souhaite que throwingMerger(), de la même manière que l’implémentation de base toMap comme suit:

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

Quelle serait la méthode la plus pratique d’utiliser Collectors pour renvoyer un SortedMap?

56
Robert Bain

Je ne pense pas que tu puisses aller beaucoup mieux que ça:

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

throw lambda est identique à throwingMerger() mais je ne peux pas l'appeler directement car il s'agit d'un paquet privé (vous pouvez bien sûr toujours créer votre propre méthode statique comme celle de throwingMerger())

54
dkatzel

Sur la base de la confirmation par dkatzel qu'il n'y a pas de méthode API Nice, j'ai choisi de maintenir ma propre classe Collectors personnalisée:

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

Il semble qu'il n'y ait pas de moyen standard de le faire sans définir votre propre méthode throwingMerger() ou utiliser explicitement lambda. Dans ma bibliothèque StreamEx, j'ai défini la méthode toSortedMap qui utilise également utilise my own throwingMerger().

7
Tagir Valeev

Pour ce faire, vous pouvez également permettre à Collectors.toMap () de renvoyer la carte qu'il va renvoyer, puis de la transmettre à une nouvelle TreeMap <> ().

La mise en garde il est que cela ne fonctionne que si votre "hashCode () + equals ()" et "compareTo" sont cohérents. S'ils ne sont pas cohérents, alors HashMap supprimera un ensemble de clés différent de celui de votre TreeMap.

4
Daniel

Si vous utilisez la bibliothèque goyave, vous pouvez utiliser:

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

La carte obtenue sera une SortedMap et sera également immuable. 

0
uwe