14

ArrayList inherits equals implementation from its parent class AbstractList which is not very effective.

It could first check the size of the two ArrayLists and then return false immediately if these sizes are different. Why does not ArrayList do that?

Maroun
  • 94,125
  • 30
  • 188
  • 241
ZhekaKozlov
  • 36,558
  • 20
  • 126
  • 155
  • Try reading this thread http://programmers.stackexchange.com/questions/239139/why-do-arrays-in-java-not-override-equals – Avihoo Mamka Feb 22 '16 at 09:13
  • 1
    I don't think that [this](http://stackoverflow.com/questions/18958113/jdk-implementation-of-abstractlistequals-does-not-check-for-list-size-equali) question is a duplicate, voted for reopen. – Maroun Feb 23 '16 at 07:25

2 Answers2

7

As noted in this answer, this is not done because some implementations has O(n) complexity of their size method, so this can be indeed a degradation.

I agree that making equals consistent in all lists implementations can affect collections that has O(1) size complexity, but maybe Java developers thought that it's much easier to insert it when you need than removing it when you don't (you'll have to re-implement the whole method!). For example, you can easily add this optimization with something like:

public boolean equals(Object o) {
    // here it is
    if (o instanceof List && this.size() != ((List)o).size())
        return false;

    // call the parent equals
    return super.equals(o);

But if it was originally implemented with the size check (in the abstract class), you had to re-implement the whole method and remove the size check:

public boolean equals(Object o) {
    if (o == this)
        return true;
    if (!(o instanceof List))
        return false;

    ListIterator<E> e1 = listIterator();
    ListIterator<?> e2 = ((List<?>) o).listIterator();
    while (e1.hasNext() && e2.hasNext()) {
        E o1 = e1.next();
        Object o2 = e2.next();
        if (!(o1==null ? o2==null : o1.equals(o2)))
            return false;
    }
    return !(e1.hasNext() || e2.hasNext());
}
Community
  • 1
  • 1
Maroun
  • 94,125
  • 30
  • 188
  • 241
  • 1
    Ah, what I missed when I was thinking about it - whilst the default implementation of `size()` is `O(1)`, it is not `final`, so you cannot guarantee that it has not been overridden. Obvs. – Andy Turner Feb 22 '16 at 09:18
  • Maybe I'm not yet awake, but ... couldn't you just call `return super.equals(o);` instead of manually doing the iteration? – Marco13 Feb 22 '16 at 09:43
2

Finally, a decision to override ArrayList.equals() and ArrayList.indexOf() was made: https://bugs.openjdk.java.net/browse/JDK-8196340. Benchmarks show a tangible performance gain.

ZhekaKozlov
  • 36,558
  • 20
  • 126
  • 155