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

Inconsistency between API documentation and TreeSet.add(...) behaviour

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Unresolved
    • Icon: P4 P4
    • None
    • 6
    • core-libs

      FULL PRODUCT VERSION :
        From Linux:
      java version "1.7.0"
      IcedTea Runtime Environment (build 1.7.0-b21)
      IcedTea 64-bit Server VM (build 1.7.0-b21)

      ADDITIONAL OS VERSION INFORMATION :
      Microsoft Windows XP [Version 5.1.2600]
      Linux 2.6.22-14-generic #1 SMP Tue Feb 12 02_46_46 UTC 2008 x86_64 GNU/Linux
      and probably all others!

      A DESCRIPTION OF THE PROBLEM :
      API documentation for TreeSet.add(E e) is not consistent with class behaviour.

      The documentation states that: "Adds the specified element to this set if it is not already present. More formally, adds the specified element e to this set if the set contains no element e2 such that (e==null ? e2==null : e.equals(e2))."

      However, the implementation does not actually use equals, it uses compareTo; an equivalent statement of the actual behaviour would be as follows: "Adds the specified element to this set if it is not already present. More formally, adds the specified element e to this set if the set contains no element e2 such that (e==null ? e2==null : e.compareTo(e2)==0)."

      These two are NOT equivalent, since there is no strict requirement on compareTo to be consistent with equals (see documentation for interface Comparable).

      Although this behaviour means that TreeSet and other set implementations (e.g. HashSet) have different mechanisms for detecting equality of members, a fix for this might not be considered backwards compatible (despite being consistent with existing documentation), so my request is simply for a change to the documentation as suggested above.

      There may be other methods (addAll?) which display the same mismatch between advertised and actual behaviour, but I've not checked them.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Create a class which implements Comparable, and override Object.equals such that e1.compareTo(e2)==0 and e1.equals(e2)==true are not synonymous. For a quick test, make equals always return false and compareTo always return zero.


      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      Expected behaviour (to be consistent with the documentation) is that insertion of multiple such objects into either a TreeSet or a HashSet will succeed, since both claim reliance on equals to determine uniqueness.

      ACTUAL -
      Iow, inserting multiple such objects into a TreeSet will fail (contrary to the documentation), while inserting them into a HashSet will succeed.


      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      /*
       * Please excuse all the statics! It's a quick and dirty demo. If TreeSet were compatible
       * with its documentation, then any selection of objects which could successfully be added
       * to a HashSet (i.e. there exist no members a,b such that a.equals(b)) could also be added
       * to a TreeSet. The fact that this is not the case demonstrates the inconsistency between
       * the documentation and implementation of TreeSet.
       */


      import java.util.HashSet;
      import java.util.TreeSet;

      public class TreeSetTest {

      /*
      * This inner class deliberately has a compareTo method that is not consistent with equals
      */
      static class TestObject implements Comparable<TestObject> {
      @Override
      public int compareTo(TestObject arg0) {
      // No two of these objects can be ordered
      return 0;
      }

      @Override
      public boolean equals(Object arg0) {
      // No two of these objects are ever equal to each other
      return false;
      }
      }

      public static void printSuccess(boolean success) {
      if (success) System.out.println(" Success");
      else System.out.println(" Failure");
      }

      public static void main(String[] args) {
      TreeSet<TestObject> testTreeSet = new TreeSet<TestObject>();
      HashSet<TestObject> testHashSet = new HashSet<TestObject>();

      System.out.println("Adding to the HashSet:");
      printSuccess(testHashSet.add(new TestObject()));
      printSuccess(testHashSet.add(new TestObject()));
      printSuccess(testHashSet.add(new TestObject()));

      System.out.println("Copying to the TreeSet:");
      for (TestObject to : testHashSet) {
      printSuccess(testTreeSet.add(to));
      }
      }
      }

      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      No workaround, except to be aware that classes for which compareTo is not compatible with equals will NOT display the advertised behaviour when added to a TreeSet.

            Unassigned Unassigned
            ndcosta Nelson Dcosta (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Imported:
              Indexed: