Ярлык для отображения потока на карту с помощью идентификационного ключа - PullRequest
2 голосов
/ 02 июля 2019

Рассмотрим следующий пример кода, обрабатывающий список строк, сопоставляя каждую строку с ее длиной и печатая каждую запись сопоставления

package com.dbenergie.ndm.bnb.business;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

public class Application {

    public static void main(String[] args) {
        final List<String> strings = Arrays.asList("Hello", "World", "!");

        // 1
        final Map<String, Integer> stringCharacterCountMapping = strings.stream()
                .collect(Collectors.toMap(Function.identity(), String::length));

        stringCharacterCountMapping.entrySet().stream().forEach(System.out::println);
    }
}

Теперь, что я лично нахожу довольно грязным или шаблонным, так это явное отображение каждой записи потока в качестве ключа карты с использованием Function.identity() (в 1), но для каждого обнаруженного мной сборщика отображений требуется средство отображения ключей - есть ли какой-то коллектор, который я пропустил, или мне нужно определить свой собственный коллектор, если мне это понадобится? Было бы очень удобно иметь что-то вроде

Collectors.toMap(String::length);

или аналогичный. Есть идеи?

1 Ответ

3 голосов
/ 02 июля 2019

В классе Collectors нет метода toMap, который не принимает keyMapper. Я подозреваю, что это потому, что он может быть весьма неоднозначным, какой единственный аргумент вы передаете в карты к. Значение или ключ?

Вы легко можете написать такой сборщик самостоятельно:

class MyCollectors {
    public static <K, U> Collector<K, ?, Map<K,U>> toMapWithValueWrapper(Function<? super K, ? extends U> valueMapper) {
        return Collectors.toMap(Function.identity(), valueMapper);
    }
}

Обратите внимание, что подпись немного отличается от Collectors.toMap. Есть только 2 общих параметра. Оригинал Collectors.toMap имеет 3 - T (тип, который мы собираем), K (тип ключа) и U (тип значения). Поскольку вы используете функцию идентификации для ключа, ключ всегда будет иметь тот же тип, что и тип, который мы собираем, поэтому T == K. Следовательно, мы можем устранить T.

Edit:

Как предложил Хольгер в комментариях, нам не нужно форсировать T == K, потому что T может быть подклассом K, и вы все равно можете использовать функцию идентификации для отображения с T на K , Поэтому вы можете использовать это:

class MyCollectors {
    public static <T extends K, K, U> Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends U> valueMapper) {
        return Collectors.toMap(Function.identity(), valueMapper);
    }
}

если вы хотите разрешить собирать на карту, тип ключа которой является суперклассом типа, который вы собираете.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...