I would suggest looking into Guava's MultiMap which makes your use-case easier to deal with (providing lots of optimizations and extra functionality you may want to obtain later down the road)
Edit:
An example of why Multimap makes more sense than, say, using the computeIfAbsent approach:
1. each key has a list of a certain size, what if you'll want to get the "total" size in the future? you would have to create some logic to achieve this with good performance (or use a method that takes O(keys))
2. at the moment you're only putting things into the map, but what happens if you want to remove things from the map in the future? You will need to write some boilerplate code (that is easy to get wrong) to make sure that removing values doesn't cause a memory leak
There are other things to gain from using a multimap but these are just two easy to explain benefits.
Edit 2:
An example using your input:
import java.util.Arrays;
import java.util.List;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ListMultimap;
public class Example {
public static class EntityCompositeId {
@Override
public String toString() {
return "EntityCompositeId [firstId=" + firstId + ", secondId=" + secondId + "]";
}
public EntityCompositeId(Long firstId, Long secondId) {
super();
this.firstId = firstId;
this.secondId = secondId;
}
private Long firstId;
public Long getFirstId() {
return firstId;
}
private Long secondId;
}
public static class EntityComposite {
@Override
public String toString() {
return "EntityComposite [id=" + id + ", first=" + first + ", second=" + second + "]";
}
public EntityComposite(EntityCompositeId id, String first, String second) {
super();
this.id = id;
this.first = first;
this.second = second;
}
private EntityCompositeId id;
public EntityCompositeId getId() {
return id;
}
private String first;
private String second;
}
public static void main(String[] args) {
List<EntityComposite> listEntityComposite = Arrays.asList(
new EntityComposite(new EntityCompositeId(1l, 1l), "firstA", "secondBirdOne"),
new EntityComposite(new EntityCompositeId(1l, 2l), "firstA", "secondBirdTwo"),
new EntityComposite(new EntityCompositeId(1l, 3l), "firstA", "secondBirdThree"),
new EntityComposite(new EntityCompositeId(2l, 1l), "firstB", "secondCatOne"),
new EntityComposite(new EntityCompositeId(2l, 2l), "firstB", "secondCatTwo"),
new EntityComposite(new EntityCompositeId(2l, 3l), "firstB", "secondCatThree"),
new EntityComposite(new EntityCompositeId(3l, 1l), "firstC", "secondDogOne"),
new EntityComposite(new EntityCompositeId(3l, 2l), "firstC", "secondDogTwo"),
new EntityComposite(new EntityCompositeId(3l, 3l), "firstC", "secondDogThree"));
ListMultimap<Long, EntityComposite> map = ArrayListMultimap.create();
listEntityComposite.forEach(entityComposite -> map.put(entityComposite.getId().getFirstId(), entityComposite));
map.keySet().forEach(key -> System.out.println(map.get(key)));
}
}
Yields the following output:
[EntityComposite [id=EntityCompositeId [firstId=1, secondId=1], first=firstA, second=secondBirdOne], EntityComposite [id=EntityCompositeId [firstId=1, secondId=2], first=firstA, second=secondBirdTwo], EntityComposite [id=EntityCompositeId [firstId=1, secondId=3], first=firstA, second=secondBirdThree]]
[EntityComposite [id=EntityCompositeId [firstId=2, secondId=1], first=firstB, second=secondCatOne], EntityComposite [id=EntityCompositeId [firstId=2, secondId=2], first=firstB, second=secondCatTwo], EntityComposite [id=EntityCompositeId [firstId=2, secondId=3], first=firstB, second=secondCatThree]]
[EntityComposite [id=EntityCompositeId [firstId=3, secondId=1], first=firstC, second=secondDogOne], EntityComposite [id=EntityCompositeId [firstId=3, secondId=2], first=firstC, second=secondDogTwo], EntityComposite [id=EntityCompositeId [firstId=3, secondId=3], first=firstC, second=secondDogThree]]