在Java 8中如何转换地图<K,V>到另一张地图<K,V>使用lambda?

original title: "In Java 8 how do I transform a Map<K,V> to another Map<K,V> using a lambda?"


Translate

I've just started looking at Java 8 and to try out lambdas I thought I'd try to rewrite a very simple thing I wrote recently. I need to turn a Map of String to Column into another Map of String to Column where the Column in the new Map is a defensive copy of the Column in the first Map. Column has a copy constructor. The closest I've got so far is:

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

but I'm sure there must be a nicer way to do it and I'd be grateful for some advice.



我刚刚开始研究Java 8,并尝试了lambda,我认为我会尝试重写最近写的一本非常简单的东西。我需要将字符串映射到列转换为另一个字符串映射...

这是翻译后的摘要,如果您需要查看完整的翻译,请单击“Translate”图标


所有的回答
  • Translate

    You could use a 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) {}
      }
    }
    

  • Translate
    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}
    

    You can use the forEach method to do what you want.

    What you're doing there is:

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

    Which we can simplify into a lambda:

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

    And because we're just calling an existing method we can use a method reference, which gives us:

    map.forEach(map2::put);
    

  • Translate

    The way without re-inserting all entries into the new map should be the fastest it won't because HashMap.clone internally performs rehash as well.

    Map<String, Column> newColumnMap = originalColumnMap.clone();
    newColumnMap.replaceAll((s, c) -> new Column(c));
    

  • Translate

    Keep it Simple and use 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())
                                      );
    

  • Translate

    Here is another way that gives you access to the key and the value at the same time, in case you have to do some kind of transformation.

    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));
    

  • Translate

    If you use Guava (v11 minimum) in your project you can use Maps::transformValues.

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

  • Translate

    If you don't mind using 3rd party libraries, my cyclops-react lib has extensions for all JDK Collection types, including Map. You can directly use the map or bimap methods to transform your Map. A MapX can be constructed from an existing Map eg.

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

    If you also wish to change the key you can write

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

    bimap can be used to transform the keys and values at the same time.

    As MapX extends Map the generated map can also be defined as

      Map<String, Column> y