-
Type:
Enhancement
-
Resolution: Unresolved
-
Priority:
P4
-
Affects Version/s: None
-
Component/s: core-libs
-
None
The equals() method of AbstractImmutableList could be optimized.
It's currently mostly a copy of AbstractList.equals(), which performs the obvious initial checks on the argument of == and instanceof List. However, it does NOT check the size of this against the argument's size. This was proposed but rejected previously (seeJDK-6197431 and JDK-8179940). The reason is AbstractList's implementation behavior is defined precisely and is relied upon by subclasses, so changing the behavior (even in apparently innocuous ways) could result in incompatibility.
However, this compatibility argument doesn't apply to AbstractImmutableList, since it cannot be publicly subclassed. Therefore, some behavior changes are permissible.
A secondary issue with calling size() is that sometimes it requires a full iteration of the argument to determine the size, and it's thus O(n) with no possibility of early termination. This does apply to some collections, e.g. submaps of TreeMap, but I'm not aware of any List implementations for which size() is O(n).
So, it might be reasonable to perform an early size() check on this vs the argument and return false if they're unequal.
Another possibility is to check the argument for RandomAccess and if the argument is RandomAccess, perform a for-loop with get(i) instead of creating iterators ('this' is always RandomAccess). One wrinkle is what happens if the argument changes size during the loop. If the argument List gets larger, the lists are unequal, though presumably they were equal at some point in the past, if the first N elements were checked. If the argument List gets smaller, get(i) will throw IOOBE. This could be caught and then return false. One hopes that adding a try/catch doesn't defeat any optimizations that a for-loop might afford.
It's currently mostly a copy of AbstractList.equals(), which performs the obvious initial checks on the argument of == and instanceof List. However, it does NOT check the size of this against the argument's size. This was proposed but rejected previously (see
However, this compatibility argument doesn't apply to AbstractImmutableList, since it cannot be publicly subclassed. Therefore, some behavior changes are permissible.
A secondary issue with calling size() is that sometimes it requires a full iteration of the argument to determine the size, and it's thus O(n) with no possibility of early termination. This does apply to some collections, e.g. submaps of TreeMap, but I'm not aware of any List implementations for which size() is O(n).
So, it might be reasonable to perform an early size() check on this vs the argument and return false if they're unequal.
Another possibility is to check the argument for RandomAccess and if the argument is RandomAccess, perform a for-loop with get(i) instead of creating iterators ('this' is always RandomAccess). One wrinkle is what happens if the argument changes size during the loop. If the argument List gets larger, the lists are unequal, though presumably they were equal at some point in the past, if the first N elements were checked. If the argument List gets smaller, get(i) will throw IOOBE. This could be caught and then return false. One hopes that adding a try/catch doesn't defeat any optimizations that a for-loop might afford.