Вот несколько вариантов ответа Сотириоса Делиманолиса , который был довольно хорош для начала (+1). Учтите следующее:
static <X, Y, Z> Map<X, Z> transform(Map<? extends X, ? extends Y> input,
Function<Y, Z> function) {
return input.keySet().stream()
.collect(Collectors.toMap(Function.identity(),
key -> function.apply(input.get(key))));
}
Пара очков здесь. Во-первых, это использование подстановочных знаков в генериках; это делает функцию несколько более гибкой. Подстановочный знак был бы необходим, если, например, вы хотите, чтобы у выходной карты был ключ, который является суперклассом ключа входной карты:
Map<String, String> input = new HashMap<String, String>();
input.put("string1", "42");
input.put("string2", "41");
Map<CharSequence, Integer> output = transform(input, Integer::parseInt);
(Существует также пример значений карты, но он действительно надуманный, и я признаю, что использование ограниченного символа подстановки для Y помогает только в крайних случаях.)
Второй момент заключается в том, что вместо запуска потока над входной картой entrySet
я запускал его через keySet
. Это делает код немного чище, я думаю, за счет необходимости извлекать значения из карты, а не из записи карты. Между прочим, у меня изначально был key -> key
первый аргумент, toMap()
и по какой-то причине это не удалось с ошибкой вывода типа. Поменял его на (X key) -> key
работавший, как и сделал Function.identity()
.
Еще один вариант заключается в следующем:
static <X, Y, Z> Map<X, Z> transform1(Map<? extends X, ? extends Y> input,
Function<Y, Z> function) {
Map<X, Z> result = new HashMap<>();
input.forEach((k, v) -> result.put(k, function.apply(v)));
return result;
}
Это использует Map.forEach()
вместо потоков. Это еще проще, я думаю, потому что это обходится без коллекционеров, которые несколько неуклюжи для использования с картами. Причина в том, что Map.forEach()
ключ и значение задаются как отдельные параметры, тогда как поток имеет только одно значение - и вам нужно выбрать, использовать ли ключ или запись карты в качестве этого значения. С другой стороны, этому не хватает богатого, плавного совершенства других подходов. :-)
e -> e.getKey()
наMap.Entry::getKey
. Но это вопрос вкуса / стиля программирования.