it-swarm.com.ru

Java 8 Collectors.toMap SortedMap

Я использую лямбды Java 8 и хочу использовать CollectorstoMap для возврата SortedMap. Лучшее, что я могу придумать, - это вызвать следующий метод CollectorstoMap с фиктивными mergeFunction и mapSupplier, равными 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);
}

Я не хочу передавать функцию слияния, так как я просто хочу throwingMerger(), так же, как базовую toMapimplementation, следующим образом:

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

Каков наилучший метод использования Collectors для возврата SortedMap?

56
Robert Bain

Я не думаю, что вы можете стать намного лучше, чем это:

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

где throw лямбда - это то же самое, что throwingMerger(), но я не могу напрямую вызвать это, так как это закрытый пакет (вы, конечно, всегда можете сделать свой собственный статический метод для такого типа, как throwingMerger()).

54
dkatzel

Основываясь на подтверждении dkatzel, что метод Nice API отсутствует, я решил сохранить свой собственный класс Collectors:

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

Кажется, что не существует стандартного способа сделать это без определения собственного метода throwingMerger() или использования явной лямбды. В моей библиотеке StreamEx я определил toSortedMap метод, который также использует мою собственную throwingMerger().

7
Tagir Valeev

Другой способ сделать это - разрешить Collectors.toMap () возвращать любую карту, которую он собирается вернуть, а затем передать ее в новый TreeMap <> ().

Предостережение заключается в том, что это работает только в том случае, если ваши hashCode () + equals () и compareTo согласованы. Если они не согласованы, то в результате вы получите HashMap, удаляющий другой набор ключей, чем ваш TreeMap.

4
Daniel

Если вы используете библиотеку guava, то вы можете использовать:

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

Полученная карта будет SortedMap и также неизменной. 

0
uwe