在Java 8中,如何使用lambda将Map <K,V>转换为另一个Map <K,V>?

ann*_*eir 126 java lambda map java-8 java-stream

我刚刚开始研究Java 8并试用lambdas我以为我会尝试重写一个我最近编写的非常简单的东西.我需要将String of Map转换为Column到另一个String to Column的Map,其中新Map中的Column是第一个Map中Column的防御副本.列具有复制构造函数.我到目前为止最接近的是:

    Map<String, Column> newColumnMap= new HashMap<>();
    originalColumnMap.entrySet().stream().forEach(x -> newColumnMap.put(x.getKey(), new Column(x.getValue())));
Run Code Online (Sandbox Code Playgroud)

但我相信必须有一个更好的方法去做,我会感激一些建议.

McD*_*ell 196

您可以使用收集器:

import java.util.*;
import java.util.stream.Collectors;

public class Defensive {

  public static void main(String[] args) {
    Map<String, Column> original = new HashMap<>();
    original.put("foo", new Column());
    original.put("bar", new Column());

    Map<String, Column> copy = original.entrySet()
        .stream()
        .collect(Collectors.toMap(Map.Entry::getKey,
                                  e -> new Column(e.getValue())));

    System.out.println(original);
    System.out.println(copy);
  }

  static class Column {
    public Column() {}
    public Column(Column c) {}
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 我认为上面要注意的重要(且有点违反直觉)的事情是,转换是在收集器中进行的,而不是在map()流操作中进行的 (3认同)

小智 22

Map<String, Integer> map = new HashMap<>();
map.put("test1", 1);
map.put("test2", 2);

Map<String, Integer> map2 = new HashMap<>();
map.forEach(map2::put);

System.out.println("map: " + map);
System.out.println("map2: " + map2);
// Output:
// map:  {test2=2, test1=1}
// map2: {test2=2, test1=1}
Run Code Online (Sandbox Code Playgroud)

您可以使用该forEach方法执行您想要的操作.

你在做什么是:

map.forEach(new BiConsumer<String, Integer>() {
    @Override
    public void accept(String s, Integer integer) {
        map2.put(s, integer);     
    }
});
Run Code Online (Sandbox Code Playgroud)

我们可以将其简化为lambda:

map.forEach((s, integer) ->  map2.put(s, integer));
Run Code Online (Sandbox Code Playgroud)

因为我们只是调用现有方法,所以我们可以使用方法引用,它为我们提供:

map.forEach(map2::put);
Run Code Online (Sandbox Code Playgroud)

  • 我喜欢你如何解释这里幕后发生的事情,它让它更加清晰.但我认为这只是给我原始地图的直接副本,而不是新的地图,其中的价值已变成防御性副本.我是否正确地理解了我们可以使用(map2 :: put)的原因是相同的参数进入lambda,例如(s,整数)和put方法一样?所以要做一个防御性的副本,它需要是`originalColumnMap.forEach((string,column) - > newColumnMap.put(string,new Column(column)));`或者我可以缩短它吗? (7认同)

lev*_*tov 12

没有将所有条目重新插入新映射的方式应该是最快的,因为HashMap.clone内部也会执行rehash.

Map<String, Column> newColumnMap = originalColumnMap.clone();
newColumnMap.replaceAll((s, c) -> new Column(c));
Run Code Online (Sandbox Code Playgroud)

  • 这种方法的优点是保持了`Map`实现的行为,即如果`Map`是一个'EnumMap`或`SortedMap`,那么得到的`Map`也是如此.如果使用特殊的`Comparator`的`SortedMap`,它可能会产生巨大的语义差异.哦,这同样适用于`IdentityHashMap` ...... (2认同)

小智 7

保持简单并使用Java 8: -

 Map<String, AccountGroupMappingModel> mapAccountGroup=CustomerDAO.getAccountGroupMapping();
 Map<String, AccountGroupMappingModel> mapH2ToBydAccountGroups = 
              mapAccountGroup.entrySet().stream()
                         .collect(Collectors.toMap(e->e.getValue().getH2AccountGroup(),
                                                   e ->e.getValue())
                                  );
Run Code Online (Sandbox Code Playgroud)


Luc*_*oss 6

这是另一种方法,可以让您同时访问键和值,以防您必须进行某种转换。

Map<String, Integer> pointsByName = new HashMap<>();
Map<String, Integer> maxPointsByName = new HashMap<>();

Map<String, Double> gradesByName = pointsByName.entrySet().stream()
        .map(entry -> new AbstractMap.SimpleImmutableEntry<>(
                entry.getKey(), ((double) entry.getValue() /
                        maxPointsByName.get(entry.getKey())) * 100d))
        .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
Run Code Online (Sandbox Code Playgroud)


And*_*nzo 6

如果您在项目中使用 Guava(最低 v11),您可以使用Maps::transformValues

Map<String, Column> newColumnMap = Maps.transformValues(
  originalColumnMap,
  Column::new // equivalent to: x -> new Column(x) 
)
Run Code Online (Sandbox Code Playgroud)

注意:此地图的值是惰性计算的。如果转换很昂贵,您可以像 Guava 文档中建议的那样将结果复制到新地图。

To avoid lazy evaluation when the returned map doesn't need to be a view, copy the returned map into a new map of your choosing.
Run Code Online (Sandbox Code Playgroud)