Подтвердить что ты не робот

Java 8 Collectors.toMap SortedMap

Я использую Java 8 lambdas и хочу использовать Collectors toMap для возврата SortedMap. Лучшее, что я могу придумать, - вызвать следующий метод Collectors toMap с фиктивным 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(), так же как и базовая реализация toMap следующим образом:

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?

4b9b3361

Ответ 1

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

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

Ответ 2

Основываясь на подтверждении dkatzel, что нет хорошего 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);
    }

}

Ответ 3

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

Ответ 4

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

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