使用流,如何在HashMap中映射值?
给定一个Map
,其中Person上有一个String getName()
(etc)方法,如何将Map
转换为Map
,其中String
是从调用Person::getName()
?
我会使用Pre-Java 8
Map byNameMap = new HashMap(); for (Map.Entry person : people.entrySet()) { byNameMap.put(person.getKey(), person.getValue().getName()); }
但我想用流和lambdas来做。
我无法看到如何以function样式执行此操作:Map / HashMap不实现Stream
。
people.entrySet()
返回一个Set<Entry>
我可以流过,但是如何将新的Entry
到目标映射?
使用Java 8,您可以:
Map byNameMap = new HashMap<>(); people.forEach((k, v) -> byNameMap.put(k, v.getName());
虽然你最好使用Guava的Maps.transformValues ,它包装原始Map
并在你执行get
时进行转换,这意味着你只需在实际使用该值时支付转换成本。
使用Guava看起来像这样:
Map byNameMap = Maps.transformValues(people, Person::getName);
编辑:
关注@ Eelco的评论(以及完整性),使用Collectors.toMap更好地转换为地图:
Map byNameMap = people.entrySet() .stream() .collect(Collectors.toMap(Map.Entry::getKey, (entry) -> entry.getValue().getName());
一种方法是使用toMap
收集器:
import static java.util.stream.Collectors.toMap; Map byNameMap = people.entrySet().stream() .collect(toMap(Entry::getKey, e -> e.getValue().getName()));
使用一些通用代码,我在手头的库中遗憾地找不到它
public static Map remap(Map map, Function super V1, ? extends V2> function) { return map.entrySet() .stream() // or parallel .collect(Collectors.toMap( Map.Entry::getKey, e -> function.apply(e.getValue()) )); }
这与Guavas Maps.transformValues
基本相同,减去了其他人提到的缺点。
Map persons = ...; Map byNameMap = remap(persons, Person::getName);
如果您需要密钥以及重映射function中的值,则第二个版本可以实现
public static Map remap(Map map, BiFunction super K, ? super V1, ? extends V2> function) { return map.entrySet() .stream() // or parallel .collect(Collectors.toMap( Map.Entry::getKey, e -> function.apply(e.getKey(), e.getValue()) )); }
它可以用作例如
Map byNameMap = remap(persons, (key, val) -> key + ":" + val.getName());