-
Enhancement
-
Resolution: Not an Issue
-
P4
-
None
-
21
-
generic
-
generic
ADDITIONAL SYSTEM INFORMATION :
Linux version 6.2.9-300.fc38.x86_64 (mockbuild@38f30b3c0c69453fae61718fc43f33bc)
(gcc (GCC) 13.0.1 20230318 (Red Hat 13.0.1-0), GNU ld version 2.39-9.fc38) #1 S
MP PREEMPT_DYNAMIC Thu Mar 30 22:32:58 UTC 2023
A DESCRIPTION OF THE PROBLEM :
Set.contains() java doc says :
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 Objects.equals(o, e).
However, this is not actually true. The Objects.equals() returns true even if the object has no hashcode or a mismatched hashcode and Sets.contains() will still return false.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the attached class
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Note if you uncomment the hashcode in the inner class this will start working as expected.
With it commented out, Objects.equals() still returns true, yet contains will return false.
I understand the technical reasoning for this, and why it must be, I'm just saying the Javadocs could possibly be clarified to match the implementation details.
---------- BEGIN SOURCE ----------
import java.util.HashSet;
import java.util.Objects;
public class Test
{
public static class Temp
{
public String name;
public long number=System.nanoTime();
public Temp(String s)
{
name=s;
}
// @Override
// public int hashCode()
// {
// return Objects.hash(name);
// }
@Override
public boolean equals(Object obj)
{
if (this == obj) return true;
if (obj == null) return false;
if (getClass() != obj.getClass()) return false;
Temp other = (Temp) obj;
return Objects.equals(name, other.name);
}
}
public static void main(String... argv) throws Exception
{
System.err.println(System.getProperty("java.runtime.name")+ " : " +System.getProperty("java.runtime.version"));
HashSet<Temp> set1=new HashSet<>();
HashSet<Temp> set2=new HashSet<>();
set1.add(new Temp("asdf"));
set2.add(new Temp("asdf"));
// javadoc : If so, it returns containsAll((Collection) o)
System.err.println("set equals (expected true) : " + set1.equals(set2));
System.err.println("set1 : "+set1);
System.err.println("set2 : "+set2);
System.err.println("set elements equals : " + set1.toArray()[0].equals(set2.toArray()[0]));
// javadoc : This implementation iterates over the specified collection, checking each element returned by the iterator in turn to see if it's contained in this collection
System.err.println("set contains all (expected true) : " +set1.containsAll(set2));
// javaDoc : 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 Objects.equals(o, e).
System.err.println("set contains (expected true) : "+set1.contains(set2.toArray()[0]));
System.err.println("object equals : " +Objects.equals(set2.toArray()[0],set1.toArray()[0]));
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
fix the Javadocs to note that object.equals()==true AND hashcode must be equals.
Linux version 6.2.9-300.fc38.x86_64 (mockbuild@38f30b3c0c69453fae61718fc43f33bc)
(gcc (GCC) 13.0.1 20230318 (Red Hat 13.0.1-0), GNU ld version 2.39-9.fc38) #1 S
MP PREEMPT_DYNAMIC Thu Mar 30 22:32:58 UTC 2023
A DESCRIPTION OF THE PROBLEM :
Set.contains() java doc says :
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 Objects.equals(o, e).
However, this is not actually true. The Objects.equals() returns true even if the object has no hashcode or a mismatched hashcode and Sets.contains() will still return false.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the attached class
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Note if you uncomment the hashcode in the inner class this will start working as expected.
With it commented out, Objects.equals() still returns true, yet contains will return false.
I understand the technical reasoning for this, and why it must be, I'm just saying the Javadocs could possibly be clarified to match the implementation details.
---------- BEGIN SOURCE ----------
import java.util.HashSet;
import java.util.Objects;
public class Test
{
public static class Temp
{
public String name;
public long number=System.nanoTime();
public Temp(String s)
{
name=s;
}
// @Override
// public int hashCode()
// {
// return Objects.hash(name);
// }
@Override
public boolean equals(Object obj)
{
if (this == obj) return true;
if (obj == null) return false;
if (getClass() != obj.getClass()) return false;
Temp other = (Temp) obj;
return Objects.equals(name, other.name);
}
}
public static void main(String... argv) throws Exception
{
System.err.println(System.getProperty("java.runtime.name")+ " : " +System.getProperty("java.runtime.version"));
HashSet<Temp> set1=new HashSet<>();
HashSet<Temp> set2=new HashSet<>();
set1.add(new Temp("asdf"));
set2.add(new Temp("asdf"));
// javadoc : If so, it returns containsAll((Collection) o)
System.err.println("set equals (expected true) : " + set1.equals(set2));
System.err.println("set1 : "+set1);
System.err.println("set2 : "+set2);
System.err.println("set elements equals : " + set1.toArray()[0].equals(set2.toArray()[0]));
// javadoc : This implementation iterates over the specified collection, checking each element returned by the iterator in turn to see if it's contained in this collection
System.err.println("set contains all (expected true) : " +set1.containsAll(set2));
// javaDoc : 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 Objects.equals(o, e).
System.err.println("set contains (expected true) : "+set1.contains(set2.toArray()[0]));
System.err.println("object equals : " +Objects.equals(set2.toArray()[0],set1.toArray()[0]));
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
fix the Javadocs to note that object.equals()==true AND hashcode must be equals.