简体   繁体   中英

Add to List value on HashMap

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

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

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

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM