使用流,如何在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 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 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());