171

我刚刚开始研究 Java 8 并尝试了 lambda,我想我会尝试重写我最近写的一个非常简单的东西。我需要将字符串到列的映射转换为另一个字符串到列的映射,其中新映射中的列是第一个映射中列的防御性副本。Column 有一个复制构造函数。到目前为止,我最接近的是:

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

但我确信必须有更好的方法来做到这一点,我会很感激一些建议。

4

7 回答 7

281

您可以使用Collector

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) {}
  }
}
于 2014-03-30T13:03:13.040 回答
29
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}

您可以使用该forEach方法做您想做的事。

你在那里做的是:

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

我们可以将其简化为 lambda:

map.forEach((s, integer) ->  map2.put(s, integer));

因为我们只是调用一个现有的方法,所以我们可以使用方法引用,它给了我们:

map.forEach(map2::put);
于 2014-03-30T11:13:23.817 回答
14

保持简单并使用 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())
                                  );
于 2018-02-21T11:53:58.920 回答
13

不将所有条目重新插入新地图的方式应该是最快的,因为HashMap.clone内部也会执行重新散列。

Map<String, Column> newColumnMap = originalColumnMap.clone();
newColumnMap.replaceAll((s, c) -> new Column(c));
于 2014-03-30T11:54:28.003 回答
6

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

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

注意:这个映射的值是惰性计算的。如果转换成本很高,您可以将结果复制到 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.
于 2019-05-24T10:48:17.657 回答
4

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

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));
于 2017-10-04T06:18:28.063 回答
1

如果您不介意使用 3rd 方库,我的cyclops-react库具有所有JDK Collection类型的扩展,包括Map。您可以直接使用 map 或 bimap 方法来转换您的 Map。MapX 可以从现有的 Map 构造,例如。

  MapX<String, Column> y = MapX.fromMap(orgColumnMap)
                               .map(c->new Column(c.getValue());

如果您还想更改密钥,您可以编写

  MapX<String, Column> y = MapX.fromMap(orgColumnMap)
                               .bimap(this::newKey,c->new Column(c.getValue());

bimap 可用于同时转换键和值。

随着 MapX 扩展 Map 生成的地图也可以定义为

  Map<String, Column> y
于 2016-02-24T16:13:16.240 回答