Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8326484

Set.contains() java doc does not match implementation

XMLWordPrintable

      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.

            smarks Stuart Marks
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated:
              Resolved: