I want to use the Stream API to group a list of persons by name and city. I have following code (in Java 8):
class Person {
private String name;
private String gender;
private String city;
Person(String name, String gender, String city) {
this.name = name;
this.gender = gender;
this.city = city;
}
}
class PGroup {
final String name;
final String city;
public PGroup(String name, String city) {
this.name = name;
this.city = city;
}
}
List<Person> people = new ArrayList<>();
people.add(new Person("Thomas", "M", "Cologne"));
people.add(new Person("Wilma", "F", "Cologne"));
people.add(new Person("Lydia", "F", "Munich"));
people.add(new Person("Thomas", "M", "Cologne"));
Map<PGroup, List<Person>> map = people.stream()
.collect(Collectors.groupingBy(t -> new PGroup(t.name, t.city)));
for (PGroup p : map.keySet()) {
System.out.println("name: " + p.name + ", city: " + p.city);
}
If I run this code I get:
name: Wilma, city: Cologne
name: Thomas, city: Cologne
name: Lydia, city: Munich
name: Thomas, city: Cologne
As we can see the List was not grouped at all. I expect only 3 entries, since Thomas in Cologne exists twice and we want to group by name and city:
name: Wilma, city: Cologne
name: Thomas, city: Cologne
name: Lydia, city: Munich
Why it is not grouped? What I am missing please?
Try to override the equals
and hashcode
functions of PGroup
class.
Try to replace the class code with below:
class PGroup {
final String name;
final String city;
public PGroup(String name, String city) {
this.name = name;
this.city = city;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof PGroup)) return false;
PGroup pGroup = (PGroup) o;
return Objects.equals(name, pGroup.name) && Objects.equals(city, pGroup.city);
}
@Override
public int hashCode() {
return Objects.hash(name, city);
}
}
Reason:
The default implementation of the .equals() method compares the object references or the memory location where the objects are stored in the heap. Thus by default the .equals() method checks the object by using the “==” operator. Read more on equals
and hashcode
functions here