Home > Back-end >  Java stream not putting all values of a List into a HashMap
Java stream not putting all values of a List into a HashMap

Time:04-16

I am working on a program where I need to take a list of objects and put them in a HashMap, using the class name as the key and the instance as the value.

I have the following code:

pets2.stream().forEach(pt -> animals.put(pt.getClass().getSimpleName(), pt));

Where pets2 is my list of animals is my HashMap. However, when I run this and then print the HashMap, only two objects from the list have been added into the Map.

Not even the first two, just two of them. Any idea as to what the issue is and how I can fix it?

CodePudding user response:

If you have multiple instances of the same in a list you need, you will lose information if only a single object will represent a value.

Instead, you have to group the object mapped to the same key (belonging to the same class) into a collection.

With stream API, you can do it by using the built-in collector Collectors.groupingBy(), which expects a classifier function that determines how to extract the key from an element of the stream. By default, values mapped to the same key will be grouped into a list.

Example (substitute the type Object with your super type):

List<Object> pets2 = List.of("foo", 9, "bar", 27, new HashSet<>());

Map<String, List<Object>> classNameToPet =
        pets2.stream()
             .collect(Collectors.groupingBy(obj -> obj.getClass().getSimpleName()));

classNameToPet.forEach((k, v) -> System.out.println(k   " : "   v));

Output

Integer : [9, 27]
String : [foo, bar]
HashSet : [[]]

Note :

  • The way you are using forEach() is not encouraged by the documentation, take a look at the code example provided in the paragraph "side-effects".

  • If you need to determine the actual class of your objects in order to interact with them, that means your usage inheritance is wrong. If list pets2 has a generic parameter let's say Anymal, then you don't have to discriminate between the subtypes of Anymal, but take advantage from the polymorphism.

CodePudding user response:

This would happen, if there are only two different classes in the list. Later objects with the same class as a previous on overwrite the previous one because the key is the same.

CodePudding user response:

When you are iterating over the pets2 list and adding them to the animals map (Map<String, Object>), the put operation just overwrites the already inserted value for that specific class.

Eg:

pets2 = [dog1, dog2, cat1, cat2]
// The final animals map as per your method will be
animals = [{Dog, dog2}, {Cat, cat2}]

So, to handle the case of multiple repetitions of the same class objects in the pets list, we can change the code as follows

Map<String, List<Object>> animals = new HashMap<>();
pets2.forEach(pet -> animals.computeIfAbsent(pet.getClass().getSimpleName(), p -> new ArrayList<>()).add(pet));
  • Related