Ecco alcune varianti Sotirios Delimanolis' answer, che era abbastanza buono per cominciare (+1). Considera quanto segue:
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))));
}
Un paio di punti qui. Il primo è l'uso di caratteri jolly nei generici; questo rende la funzione un po 'più flessibile. Un jolly sarebbe necessario se, ad esempio, si voleva la mappa di output di avere una chiave che è una superclasse di chiave della mappa di input:
Map<String, String> input = new HashMap<String, String>();
input.put("string1", "42");
input.put("string2", "41");
Map<CharSequence, Integer> output = transform(input, Integer::parseInt);
(C'è anche un esempio per i valori della mappa, ma è davvero artificiosa e ammetto che avere il carattere jolly limitato per Y aiuta solo nei casi limite.)
Un secondo punto è che invece di eseguire il flusso sulla mappa di input entrySet
, l'ho eseguito su keySet
. Questo rende il codice un po 'più pulito, credo, al costo di dover recuperare i valori dalla mappa anziché dalla voce della mappa. Per inciso, inizialmente ho avuto key -> key
come primo argomento a toMap()
e questo non è riuscito con un errore di inferenza di tipo per qualche motivo. La modifica in (X key) -> key
ha funzionato, così come Function.identity()
.
Ancora un'altra variante è la seguente:
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;
}
Questo utilizza Map.forEach()
invece di flussi. Questo è ancora più semplice, penso, perché dispensa con i collezionisti, che sono piuttosto goffi da usare con le mappe. Il motivo è che Map.forEach()
fornisce la chiave e il valore come parametri separati, mentre lo stream ha un solo valore e devi scegliere se utilizzare la chiave o la voce della mappa come tale valore. Sul lato negativo, questo manca della ricca, fluida bontà degli altri approcci. :-)
È possibile sostituire 'e -> e.getKey()' 'con Map.Entry :: getKey'. Ma questa è una questione di gusto/stile di programmazione. – Holger
In realtà è una questione di prestazioni, il tuo suggerimento è leggermente superiore allo "stile" lambda –