Issue
I am currently trying to get a List with unique values.
Technically, it should be really simple, and the obvious choice would be a HashSet. However, I want the properties of my "points" to be the uniqueness criteria and not their "IDs".
After that, I wanted to use the stream().distinct() method. Hoping that that one is using the overridden equals method. Sadly, this won't work either.
Any solution/Idea that works for double[] is welcome as well.
PointType Class
public class PointType{
private double x;
private double y;
public PointType(x,y){
this.x = x;
this.y = y;
}
@Override
public boolean equals(Object other){
if(other instanceof PointType && this.x == other.x && this.y==other.y){
return true;
}
return false;
}
}
I am aware of the flaw of double == double. For a minimum sample, it is sufficient.
Now to the issue:
@Test
public void testUniquness(){
Set<PointType>setA = new HashSet<>();
Set<PointType>setB = new HashSet<>();
ArrayList<PointType> listA= new ArrayList<>();
ArrayList<PointType> listB= new ArrayList<>();
PointType p1 = new PointType(1.0,2.0);
PointType p2 = new PointType(1.0,2.0);
PointType p3 = new PointType(2.0,2.0);
PointType p4 = new PointType(2.0,2.0);
// Trying to use the unique properties of a HashSet
setA.add(p1);
setA.add(p2);
setA.add(p1);
setA.add(p2);
setB.add(p1);
setB.add(p2);
setB.add(p3);
setB.add(p4);
//Now with array lists and streams.
listA.add(p1);
listA.add(p2);
listA.add(p1);
listA.add(p2);
listA = (ArraList<PointType>) listA.stream().distinct().collect(Collectors.toList());
listB.add(p1);
listB.add(p2);
listB.add(p3);
listB.add(p4);
listB = (ArraList<PointType>) listB.stream().distinct().collect(Collectors.toList());
assertTrue(p1.equals(p2)); // Test passes
assertTrue(p3.equals(p4)); // Test passes
assertTrue(setA.size() == 2); // Test passes (obviously)
assertTrue(setB.size() == 2); // Test failes. How can I use my custom equality condition?
assertTrue(listA.size() == 2); // Test passes (obviously)
assertTrue(listb.size() == 2); // Test failes. How can I use my custom equality condition?
}
Any help is appreciated.
For sure, a for loop would solve this too. But there has to be a more elegant way.
Solution
First issue, your implementation of equals
is not correct, this is what it should look like (auto-generated with IntelliJ) :
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
PointType pointType = (PointType) o;
return Double.compare(pointType.x, x) == 0 && Double.compare(pointType.y, y) == 0;
}
Second and most important problem, as the word Hash
in HashSet
suggests, you should not only implement equals
but also hashCode
, and this is not only true for hash collections but in general (every time you implement equals, you also implement hash code):
@Override
public int hashCode() {
return Objects.hash(x, y);
}
Once you have done these two things, your test using Set<PointType> setB = new HashSet<>()
will pass.
Answered By - Matteo NNZ
Answer Checked By - Willingham (JavaFixing Volunteer)