First, naming a class People is not natural, a better name would be Person.
As, for solving your problem, you can override equals and hashcode for height only like this:
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return height == person.height;
}
@Override
public int hashCode() {
return height;
}
The above assumes height is an int field. if instead, it's Integer, then you'll need to implement it like so:
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return height != null ? height.equals(person.height) : person1.height == null;
}
@Override
public int hashCode() {
return height != null ? height.hashCode() : 0;
}
Now, you can do:
Set<People> uniquePeople =
myList.stream()
.filter(Objects::nonNull)
.collect(Collectors.toSet());
or for what ever reason you don't want to override equals and hashcode you can do it with the toMap collector.
Set<Person> values = new HashSet<>(myList.stream()
.collect(Collectors.toMap(Person::getHeight, Function.identity(),
(left, right) -> left))
.values());
deciphering the above code snippet:
myList.stream()
.collect(Collectors.toMap(Person::getHeight, Function.identity(),
(left, right) -> left))
.values()
This creates a stream from myList collecting it to a map implementation, where Person::getHeight is a function extracting the person height for the map keys, Function.identity() is a function extracting a person object for the map values, (left, right) -> left) is known as the merge function meaning if two given people have the same key (height) we return the first person (left). Conversely, (left, right) -> right will return the last person in the case of key conflict.
Lastly, we pass the result of this processing to the HashSet constructor to create a Set<Person>.