Hier sind einige Variationen der Antwort von Sotirios Delimanolis , die anfangs ziemlich gut war (+1). Folgendes berücksichtigen:
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))));
}
Ein paar Punkte hier. Erstens ist die Verwendung von Platzhaltern in den Generika; Dies macht die Funktion etwas flexibler. Ein Platzhalter wäre erforderlich, wenn Sie beispielsweise möchten, dass die Ausgabekarte einen Schlüssel enthält, der eine Oberklasse des Schlüssels der Eingabekarte ist:
Map<String, String> input = new HashMap<String, String>();
input.put("string1", "42");
input.put("string2", "41");
Map<CharSequence, Integer> output = transform(input, Integer::parseInt);
(Es gibt auch ein Beispiel für die Werte der Karte, aber es ist wirklich erfunden, und ich gebe zu, dass der begrenzte Platzhalter für Y nur in Randfällen hilfreich ist.)
Ein zweiter Punkt ist, dass entrySet
ich den Stream nicht über die Eingabe-Map laufen ließ , sondern über die keySet
. Dies macht den Code meiner Meinung nach ein wenig sauberer, da Werte aus der Karte anstatt aus dem Karteneintrag abgerufen werden müssen. Übrigens hatte ich zunächst key -> key
als erstes Argument dazu toMap()
und dies schlug aus irgendeinem Grund mit einem Typinferenzfehler fehl. Es (X key) -> key
funktionierte genauso wie es funktionierte Function.identity()
.
Eine weitere Variation ist wie folgt:
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;
}
Dies verwendet Map.forEach()
anstelle von Streams. Das ist noch einfacher, denke ich, weil es auf die Sammler verzichtet, deren Verwendung mit Karten etwas umständlich ist. Der Grund dafür ist, dass Map.forEach()
der Schlüssel und der Wert als separate Parameter angegeben werden, während der Stream nur einen Wert hat - und Sie müssen auswählen, ob Sie den Schlüssel oder den Karteneintrag als diesen Wert verwenden möchten. Auf der negativen Seite fehlt dies die reiche, strömende Güte der anderen Ansätze. :-)
e -> e.getKey()
mitMap.Entry::getKey
. Aber das ist eine Frage des Geschmacks / Programmierstils.