Search code examples
javastringbuilder

StringBuilder implements Comparable but does not override equals


I don't understand this line from javadoc (under the subheading "API note"):

StringBuilder implements Comparable but does not override equals. Thus, the natural ordering of StringBuilder is inconsistent with equals.

I am a beginner in Java so could you explain this in a simple way?


Solution

  • That means StringBuilder.compareTo() and StringBuilder.equals() don't always agree.

    var sb1 = new StringBuilder("foo");
    var sb2 = new StringBuilder("foo");
    assert sb1.compareTo(sb2) == 0;      // as you would expect.
    assert sb1.equals(sb2) == true;      // surprise - it fails
    

    Now it gets a bit more confusing:

    var map = new HashMap<StringBuilder, String>();
    map.put(sb1, "lorem ipsum");
    assert map.size() == 1;
    map.put(sb2, "dolor sit amet");
    assert map.size() == 1;            // fails - it's 2
    
    var set = new TreeSet<StringBuilder>();
    set.add(sb1);
    assert set.size() == 1;
    set.add(sb2);
    assert set.size() == 2;           // you'd think this should be 2 but it fails! 
    

    That's because HashMap works with equals() whereas SortedSet with compareTo().


    NOTE 1: on equals()

    StringBuilder extends Object, which means it inherits Object.equals(); but it does not override equals(), which means StringBuilder.equals() is actually Object.equals().

    Object.equals() in turn is basically ==, ie it returns true if and only if the two objects are the same memory address.

    Object.equals() java doc


    NOTE 2: why?

    Only starting from JDK11, StringBuilder implements Comparable. Any accompanying change in equals() could have caused some older client code to break; so, I'd think, following the Java tradition of keeping things backward compatible they dropped the idea.