Making ArrayList.containsAll run faster Whenever using ArrayList, the method containsAll(collection) runs in time \$\mathcal{O}(mn)\$, where \$n\$ is the size of ArrayList and \$m\$ is the length of collection. However, it relies only on equals(Object)-method.

I have this subclass of ArrayList that does the same in time \$\mathcal{O}(n)\$, but relies on hashCode() as well.

My main question, should I do this optimization at expense of adding more requirements?

MyArrayList.java:

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;

/**
 * This class provides a faster {@link #containsAll(java.util.Collection) } 
 * method.
 * 
 * @author Rodion "rodde" Efremov
 * @version 1.6
 * @param &lt;E&gt; the actual element type.
 */
public class MyArrayList&lt;E&gt; extends ArrayList&lt;E&gt; {

    /**
     * Returns {@code true} if this list contains all elements in {@code coll}
     * and {@code false} otherwise.
     * 
     * @param  coll the collection to check for inclusion in this list.
     * @return {@code true} if this list contains all elements in 
     *         {@code coll}:
     */
    @Override
    public boolean containsAll(Collection&lt;?&gt; coll) {
        Set&lt;?&gt; set = new HashSet&lt;&gt;(coll);

        for (E element : this) {
            if (set.contains(element)) {
                set.remove(element);

                if (set.isEmpty()) {
                    return true;
                }
            }
        }

        return false;
    }

    public static void main(final String... args) {
        List&lt;Integer&gt; jdkList = new ArrayList&lt;&gt;();
        List&lt;Integer&gt; myList  = new MyArrayList&lt;&gt;();

        for (int i = 0; i &lt; 1000000; ++i) {
            jdkList.add(i);
            myList.add(i);
        }

        Random rnd = new Random();
        Collection&lt;Integer&gt; coll = new ArrayList&lt;&gt;();

        for (int i = 0; i &lt; 1000; ++i) {
            coll.add(rnd.nextInt(myList.size()));
        }

        // Uncomment for failing test.
        //coll.add(-1);

        long ta = System.currentTimeMillis();

        boolean result = jdkList.containsAll(coll);

        long tb = System.currentTimeMillis();

        System.out.println("ArrayList.containsAll() in " + (tb - ta) + " ms. " +
                           "Result: " + result);

        ta = System.currentTimeMillis();

        result = myList.containsAll(coll);

        tb = System.currentTimeMillis();

        System.out.println("MyArrayList.containsAll() in " + (tb - ta) + 
                           " ms. Result: " + result);
    }
}
Relying on .hashCode() may or may not be faster and may or may not produce the same results as relying on .equals().

Do you already see where this is going? The problem begins when you stop obeying the contract of the interface you implement. I'll quote the javadoc for contains here:


  Returns true if this collection contains the specified element. More
  formally, returns true if and only if this collection contains at
  least one element e such that (o==null ? e==null : o.equals(e)).


This is the formal definition for contains that also applies to containsAll.

Now considering that a programmer seeing a Collection expects the contains method to work based on equals and countering with the fact that yours doesn't you're violating the "Principle Of Least Surprise".

This also leads to code handling collections behaving differently depending on what implementation you pass in, which is never desirable.

In general I think that relying solely on hashCode for contains is a bad idea, even when it's best practice to override hashCode so the resulting hashes of equal objects are equal and those of nonequal objects aren't.