-
Bug
-
Resolution: Unresolved
-
P4
-
8, 9
FULL PRODUCT VERSION :
java version "1.8.0_131"
Java(TM) SE Runtime Environment (build 1.8.0_131-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.131-b11, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows [Version 10.0.15063]
A DESCRIPTION OF THE PROBLEM :
It seems that when custom Comparator is provided for TreeSet then this comparator is used to verify equality of the objects in the TreeSet when calling .contains() method. However the documentation is stating that:
"TreeSet(Comparator<? super E> comparator)
Constructs a new, empty tree set, sorted according to the specified comparator."
and
"public boolean contains(Object o)
Returns true if this set contains the specified element. More formally, returns true if and only if this set
contains an element e such that (o==null ? e==null : o.equals(e))."
which suggests that Comparator should be used only for the sorting and not for equality checks.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Please see the code sample
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Please see the code sample
ACTUAL -
Please see the code sample
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
public class Bid {
private final Integer userId;
private final Double price;
Bid(final Integer userId, final Double price){
this.userId = userId;
this.price = price;
}
Integer getUserId(){
return userId;
}
Double getPrice(){
return price;
}
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (!Bid.class.isAssignableFrom(obj.getClass())) {
return false;
}
final Bid other = (Bid) obj;
return this.userId.equals(other.userId) && this.price.equals(other.price);
}
}
TreeSet<Bid> bidsList = new TreeSet<>(Comparator.comparingDouble(Bid::getPrice));
bidsList.add(new Bid(1, 1.0));
bidsList.contains(new Bid(2, 1.0)); // this wrongly returns true and while debugging the code I can see that Bid.equals() is never invoked
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
The workaround is to include all the values from the class, that is:
TreeSet<Bid> bidsList = new TreeSet<>(Comparator.comparingDouble(Bid::getPrice).thenComparingInt(Bid::getUserId));
bidsList.add(new Bid(1, 1.0));
bidsList.contains(new Bid(2, 1.0)); // this returns false as expected
java version "1.8.0_131"
Java(TM) SE Runtime Environment (build 1.8.0_131-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.131-b11, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows [Version 10.0.15063]
A DESCRIPTION OF THE PROBLEM :
It seems that when custom Comparator is provided for TreeSet then this comparator is used to verify equality of the objects in the TreeSet when calling .contains() method. However the documentation is stating that:
"TreeSet(Comparator<? super E> comparator)
Constructs a new, empty tree set, sorted according to the specified comparator."
and
"public boolean contains(Object o)
Returns true if this set contains the specified element. More formally, returns true if and only if this set
contains an element e such that (o==null ? e==null : o.equals(e))."
which suggests that Comparator should be used only for the sorting and not for equality checks.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Please see the code sample
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Please see the code sample
ACTUAL -
Please see the code sample
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
public class Bid {
private final Integer userId;
private final Double price;
Bid(final Integer userId, final Double price){
this.userId = userId;
this.price = price;
}
Integer getUserId(){
return userId;
}
Double getPrice(){
return price;
}
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (!Bid.class.isAssignableFrom(obj.getClass())) {
return false;
}
final Bid other = (Bid) obj;
return this.userId.equals(other.userId) && this.price.equals(other.price);
}
}
TreeSet<Bid> bidsList = new TreeSet<>(Comparator.comparingDouble(Bid::getPrice));
bidsList.add(new Bid(1, 1.0));
bidsList.contains(new Bid(2, 1.0)); // this wrongly returns true and while debugging the code I can see that Bid.equals() is never invoked
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
The workaround is to include all the values from the class, that is:
TreeSet<Bid> bidsList = new TreeSet<>(Comparator.comparingDouble(Bid::getPrice).thenComparingInt(Bid::getUserId));
bidsList.add(new Bid(1, 1.0));
bidsList.contains(new Bid(2, 1.0)); // this returns false as expected
- duplicates
-
JDK-8229279 TreeSet::add method doesn't not use Objects.equals to check collision
-
- Closed
-