Java 8 here. I have the following classes:
public interface Animal {
...
}
public class Dog implements Animal {
...
}
public class Cat implements Animal {
...
}
public class Elephant implements Animal {
...
}
I have to implement the following method:
void doSomething(Map<String,Dog> dogs, Map<String,Cat> cats, Map<String,Elephant> elephants) {
// TODO:
// * Merge all dogs, cats & elephants together into the same Map<String,Animal>,
// but...
// * Do so generically (without having to create, say, a HashMap instance, etc.)
}
In my doSomething(...)
method, I need to merge all the map arguments into the same Map<String,Animal>
map, but I'd really prefer to do so without my code having to instantiate a specific map implementation (such as HashMap
, etc.).
Meaning, I know I could do this:
void doSomething(Map<String,Dog> dogs, Map<String,Cat> cats, Map<String,Elephant> elephants) {
Map<String,Animal> animals = new HashMap<>();
for(String dog : dogs.keySet()) {
animals.put(dog, dogs.get(dog));
}
for(String cat : cats.keySet()) {
animals.put(cat, cats.get(cat));
}
for(String elephant : elephants.keySet()) {
animals.put(elephant, elephants.get(elephant));
}
// Now animals has all the argument maps merged into it, but is specifically
// a HashMap...
}
I'm even fine using some utility if it exists, like maybe a Collections.merge(dogs, cats, elephants)
, etc. Any ideas?
One way to do it would be to create a stream of sets of entries and then flatmap it to have a stream of entries and collect those into a map.
Map<String,Animal> animals =
Stream.of(dogs.entrySet(), cats.entrySet(), elephants.entrySet())
.flatMap(Set::stream)
.collect(toMap(Map.Entry::getKey, Map.Entry::getValue));
//Stream.of(dogs, cats, elephants).flatMap(m -> m.entrySet().stream()) could also be an option
Also not a one-liner and without streams using Map#putAll
:
Map<String,Animal> animals = new HashMap<>(dogs);
animals.putAll(cats);
animals.putAll(elephants);
You can accomplish the task at hand with the use of Stream.Concat
:
Map<String,Animal> animals = Stream.concat(Stream.concat(dogs.entrySet().stream(), cats.entrySet().stream()), elephants.entrySet().stream())
.collect(Collectors.toMap
(
Map.Entry::getKey,
Map.Entry::getValue
)
);
You'll need to be cautious here because when merging and there are duplicate keys then an exception will be raised as expected.
The best way IMO is as in Alexis C.'s answer, with Map.putAll
:
Map<String, Animal> animals = new HashMap<>(dogs);
animals.putAll(cats);
animals.putAll(elephants);
A variant on this one:
Map<String, Animal> animals = new HashMap<>(dogs);
cats.forEach(animals::put);
elephants.forEach(animals::put);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With