Merge two maps with Java 8

Incase of a simple merge you could use map3.putAll() as explained in How can I combine two HashMap objects containing the same types?

In your case, you would probably have to write some custom logic,

First populate map3 with map1. Then Iterate the map3 to find any duplicates with map2 in which case you replace the entry with the map1.place, (map1.mark1, map2.mark2) logic.

MapMerge

public class MapMerge {

    public static void main(String []args){


        Map<String, MyObject> map1 = new HashMap<String, MyObject>();
        Map<String, MyObject> map2 = new HashMap<String, MyObject>();
        Map<String, MyObject> map3 = new HashMap<String, MyObject>();

        map3.putAll(map1);

        for(Entry<String, MyObject> entry:map2.entrySet()){         
            if (map3.containsKey(entry.getKey())){                  
                MyObject map3Obj = map3.get(entry.getKey());
                map3.put(
                    entry.getKey(), 
                    new MyObject(map3Obj.getMark1(),entry.getValue().getMark2())
                );
            }
        }
    }
}

MyObject

class MyObject{

    public MyObject(Integer m1, Integer m2){
        mark1 = m1;
        mark2 = m2;
    }

    public Integer getMark1() {
        return mark1;
    }
    public void setMark1(Integer mark1) {
        this.mark1 = mark1;
    }
    public Integer getMark2() {
        return mark2;
    }
    public void setMark2(Integer mark2) {
        this.mark2 = mark2;
    }
    Integer mark1;
    Integer mark2;
}

It can be done using the Stream API with the appropriate mergeFunction as next:

Map<String, MyObject> map3 = Stream.of(map1, map2)
    .flatMap(map -> map.entrySet().stream())
    .collect(
        Collectors.toMap(
            Map.Entry::getKey,
            Map.Entry::getValue,
            (v1, v2) -> new MyObject(v1.getMark1(), v2.getMark2())
        )
    );

This concatenates entries of map1 followed by the entries of map2, then convert everything as a Map with a merge function that will use mark1 from the first value (the one from map1) and mark2 from the second value (the one from map2) in case of duplicate keys.


Or it could also be done using a different Supplier<Map> that will propose a map that already contains the entries of map1 then we can focus only on adding the entries of map2 as next:

Map<String, MyObject> map3 = map2.entrySet()
    .stream()
    .collect(
        Collectors.toMap(
            Map.Entry::getKey,
            Map.Entry::getValue,
            (v1, v2) -> new MyObject(v1.getMark1(), v2.getMark2()),
            () -> new HashMap<>(map1)
        )
    );

Something like this should work.

Map<String, MyObject> result = new HashMap<String, MyObject>();

Set<String> allKeys = new HashSet<String>();
allKeys.addAll(map1.keySet());
allKeys.addAll(map2.keySet());
for(String key : allKeys){
    MyObject v1 = map1.get(key);
    MyObject v2 = map2.get(key);
    if(v1 != null && v2 == null){
        result.put(key, v1);
    }else if(v1 == null && v2 !=null){
        result.put(key, v2);
    } else {
        MyObject newObject = new MyObject(v1.mark1, v2.mark2); 
        result.put(key, newObject);
    }
}

Here is what I think would work

Map<String, MyObj> map3 = new HashMap<>(map1);
map2.forEach(
    (key, value) -> map3.merge(key, value, (v1, v2) -> new MyObject(v1.mark1,v2.mark2))
);

The merge function is what is taking care of your scenario 3, in that if the key already exists, it creates a new MyObject with v1.mark1 and v2.mark2