If you merge them according to the Lists' index, and both Lists have the same length, you can write:
IntStream.range(0,a.size()).forEach(i->a.get(i).putAll(b.get(i)));
This will result in List a containing the merged result.
If you want to produce a new List without mutating the original Lists, you can create new HashMaps and collect them to a new List:
List<HashMap<String,String>> c =
IntStream.range(0,a.size())
.mapToObj(i -> {
HashMap<String,String> hm = new HashMap<>(a.get(i));
hm.putAll(b.get(i));
return hm;
})
.collect(Collectors.toList());
EDIT for the updated question:
List<HashMap<String,String>> c =
a.stream ()
.map(am -> {
HashMap<String,String> hm = new HashMap<>(am);
HashMap<String,String> second =
b.stream()
.filter (bm -> bm.get ("c") != null && bm.get ("c").equals (am.get ("c")))
.findFirst()
.orElse(null);
if (second != null) {
hm.putAll (second);
}
return hm;
})
.collect(Collectors.toList());
Now we stream over the elements of the first List and for each HashMap, search for the corresponding HashMap of the second List.