Collectors.toMap с теми же ключами (распечатать тот же ключ)

У меня есть этот код для получения карты:

List<MyObject> myList = myMethod.getList();
myList.stream().collect(
    Collectors.toMap(
        MyObject::getKey, 
        MyObject::getValue,
        (e1, e2) -> {
            System.out.println("Duplicate keys !!!");
            return e1;
        }, 
        LinkedHashMap::new
    )
);

как я могу напечатать сообщение «Дубликаты ключей» с дубликатом ключа?


person liarkajn    schedule 23.11.2016    source источник
comment
я хочу написать в консоль сообщение Duplicate keys + with со значением ключа, но я не знаю как это сделать   -  person liarkajn    schedule 23.11.2016


Ответы (2)


как я могу напечатать сообщение «Дубликаты ключей» с дубликатом ключа?

С вашим текущим кодом вы получите сообщение «Повторяющиеся ключи» со списком MyObject, который содержит как минимум 2 экземпляра MyObject, которые имеют одинаковые объекты в качестве значения для getKey(), например Arrays.asList(new MyObject("foo", "bar"), new MyObject("foo", "bar2")).

Как получить соответствующий ключ?

До сих пор невозможно получить соответствующий ключ, то, что вы в настоящее время получаете от функции слияния, на самом деле представляет собой 2 значения, сопоставленные с одним и тем же ключом, которые необходимо объединить, чтобы сохранить только одно значение для соответствующего ключа.

Ваша проблема известна и исправлена ​​в Java 9, см. JDK-8040892 для более подробной информации, соответствующее исправление позволит нам получить из функции слияния как ключ, так и значения для слияния.

См. также Почему Collectors.toMap сообщает значение вместо ключа при ошибке дублирования ключа?

person Nicolas Filotto    schedule 23.11.2016
comment
Обратите внимание, что исправление затронет только коллектор toMap без явной функции слияния. Поскольку сборщик toMap по-прежнему не принимает поставщика пользовательских карт без пользовательской функции слияния, вы по-прежнему не сможете использовать явный тип карты (например, LinkedHashMap) и одновременно сообщать о дублирующихся ключах… - person Holger; 23.11.2016

Как поясняется в этом ответе, это известная проблема, которая будет исправлена ​​в Java 9 — по крайней мере, для toMap сборщик, который не принимает функцию слияния.

Поскольку функция слияния получает только два значения для слияния, а сигнатуру нельзя легко изменить, исправления для этих перегруженных методов не предвидится. К сожалению, не существует коллектора toMap, который принимает Map Supplier без явной функции слияния, поэтому, если это не изменится до выпуска, не будет исправления для вашего сценария, в котором должно быть возвращено LinkedHashMap.

Таким образом, решение состоит в том, чтобы реализовать свой собственный коллектор. Тогда вам не придется ждать Java 9 и не рисковать разочароваться.

static <T, K, V, M extends Map<K, V>> Collector<T, ?, M> toMap(
    Function<T, K> keyExtractor, Function<T, V> valueExtractor, Supplier<M> mapSupplier) {
    return Collector.of(mapSupplier,
        (m, t) -> putUnique(m, keyExtractor.apply(t), valueExtractor.apply(t)),
        (m1,m2)-> { m2.forEach((k, v) -> putUnique(m1, k, v)); return m1; }
    );
}
private static <K,V> void putUnique(Map<K,V> map, K key, V v1){
    V v2 = map.putIfAbsent(key, v1);
    if(v2 != null) throw new IllegalStateException(
        String.format("Duplicate key %s (values %s and %s)", key, v1, v2));
}

Вы можете использовать этот коллектор как

LinkedHashMap<KeyType, ValueType> map = myList.stream()
    .collect(toMap(MyObject::getKey, MyObject::getValue, LinkedHashMap::new));

или используйте квалифицированный MyCollector.toMap, относящийся к классу, в который вы поместили этот пользовательский сборщик.

person Holger    schedule 23.11.2016
comment
Спасибо, интерфейс Коллекционера был для меня немного непонятен, это хороший способ его изучить! - person Guillaume; 03.10.2017