Aqui estão algumas variações da resposta de Sotirios Delimanolis , que foi muito boa para começar (+1). Considere o seguinte:
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))));
}
Alguns pontos aqui. Primeiro é o uso de curingas nos genéricos; isso torna a função um pouco mais flexível. Um curinga seria necessário se, por exemplo, você desejasse que o mapa de saída tivesse uma chave que seja uma superclasse da chave do mapa de entrada:
Map<String, String> input = new HashMap<String, String>();
input.put("string1", "42");
input.put("string2", "41");
Map<CharSequence, Integer> output = transform(input, Integer::parseInt);
(Também há um exemplo para os valores do mapa, mas é realmente artificial, e admito que ter o curinga limitado para Y ajuda apenas em casos extremos.)
Um segundo ponto é que, em vez de executar o fluxo sobre o mapa de entrada entrySet
, eu o executei no keySet
. Isso torna o código um pouco mais limpo, eu acho, ao custo de ter que buscar valores fora do mapa, e não na entrada do mapa. Aliás, eu inicialmente tive key -> key
como o primeiro argumento toMap()
e isso falhou com um erro de inferência de tipo por algum motivo. Mudando para (X key) -> key
funcionou, assim comoFunction.identity()
.
Ainda outra variação é a seguinte:
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;
}
Isso usa em Map.forEach()
vez de fluxos. Isso é ainda mais simples, eu acho, porque dispensa os colecionadores, que são um pouco desajeitados para usar nos mapas. O motivo é que Map.forEach()
fornece a chave e o valor como parâmetros separados, enquanto o fluxo possui apenas um valor - e você deve escolher se deseja usar a chave ou a entrada do mapa como esse valor. No lado negativo, falta a bondade rica e fluida das outras abordagens. :-)
e -> e.getKey()
porMap.Entry::getKey
. Mas isso é uma questão de gosto / estilo de programação.