I'm populating a hashmap to have my objects grouped by one of their attributes. I find it “ugly” to check whether the list (the value) exists before adding my object to it.
An example will be more explicit:
// Need a map to group Person by age.
// Person = {age: int}
Map<Integer, List<Person>> myHashMap = new HashMap();
for (Person person : persons) {
int age = person.getAge();
List<Person> personsOfSameAge = myHashMap.get(age);
if (personsOfSameAge != null) {
personsOfSameAge.add(person);
} else {
personsOfSameAge = new ArrayList();
personsOfSameAge.add(person);
myHashMap.put(age, personsOfSameAge);
}
}
Is there a better way to code this?
myHashMap.addToValueListOrCreateValueList(myObject);
In Java 8, your whole code could be written like that (as other fine answers proposed):
Map<Integer, List<Person>> myHashMap = new HashMap();
for (Person person : persons) {
myHashMap.computeIfAbsent(age,age->new ArrayList<Person>()).add(person);
}
But you could be even shorter by using a stream that collects into a Map
with Collectors.groupingBy()
:
Map<Integer, List<Person>> myMap = persons.stream().collect(Collectors.groupingBy(Person:getAge));
As a side note, your actual Java 7 code could also be improved.
Of course, not as much as with Java 8 but if you cannot use Java 8, this may be interesting.
In your actual code, this is duplicated :
personsOfSameAge.add(person);
And you use two conditional statements (if
and else
) while only if
would be enough if you handle first the special case : no value in the Map
.
Here is a modified version :
Map<Integer, List<Person>> myHashMap = new HashMap<>();
for (Person person : persons) {
int age = person.getAge();
List<Person> personsOfSameAge = myHashMap.get(age);
if (personsOfSameAge == null) {
personsOfSameAge = new ArrayList();
myHashMap.put(age, personsOfSameAge);
}
personsOfSameAge.add(person);
}
Yes, there is in Java 8:
List<Person> personsOfSameAge = myHashMap.computeIfAbsent(age,age->new ArrayList<Person>());
personsOfSameAge.add(person);
Or just
myHashMap.computeIfAbsent(age,age->new ArrayList<Person>()).add(person);
Something like this ?
List<Person> newList = Optional.ofNullable( myHashMap.get(age)).orElse(new ArrayList<>());
newList.add(person);
myHashMap.put(age, newList);
Though the question involves doing it in Java 8, I'm posting this as an alternate way.
You can use MultiMap from Google Guava.
Multimap<String, Person> myHashMap = ArrayListMultimap.create();
for (Person person : persons) {
myHashMap.put(person.getAge(), person);
}
However, you have to be aware of a difference: Java's map returns null
for a non-existent key while the Google Guava's MultiMap returns an empty List
.
From javadoc for get(key) of MultiMap
Returns a view collection of the values associated with key in this multimap, if any. Note that when containsKey(key) is false, this returns an empty collection, not null. Changes to the returned collection will update the underlying multimap, and vice versa
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