Is a peculiar structural modification permissible while iterating a List using the fail-fast iterator?
kedar mhaswade
kedar.mhaswade at gmail.com
Sat Mar 24 18:13:39 UTC 2018
I apologize in advance if this has been asked before or if I am making a
rookie mistake.
Consider the program [1]. In Josh Bloch and Neal Gafter style (I miss those
Puzzlers at JavaOnes), may I ask, "What does this program print?"
As some of you may have guessed correctly, this program works *as naively
expected* in that it (erroneously) removes the desired stooge from stooges
and prints the list of remaining ones. Some analysis of the fail-fast
iterator code in java.util.AbstractList$Itr and java.util.ArrayList$Itr
suggests that only the item that is at the penultimate index in the backing
list could be removed this way (i.e. *without* the fail-fast iterator
detecting its structural modification). This appears to be because the
implementation of hasNext() only checks if the cursor is equal to size
without ensuring whether the expected and actual modification counts agree.
My confusion is whether this is specified somewhere. None of
java.util.Iterator#hasNext and java.util.ListIterator#hasNext seem to
provide any specification about this. And hence it is not clear whether or
not the hasNext() implementation must detect this peculiar structural
modification. It is *not *specified if hasNext() may not throw
ConcurrentModificationException. An unfortunate consequence is that an
oversight on programmer's part (List#remove() instead of Iterator#remove)
seems to go undetected.
Is this a bug, or a feature?
Regards,
Kedar
PS - It's entirely possible that I am not reading the code fully. I am
checked the JDK 1.8.0_131 and Open JDK 1.9.0_181 sources.
[1]
import java.util.ArrayList;import java.util.List;import static
java.util.Arrays.asList;public class ExceptionallyNamedException {
public static void main(String[] args) { List<String> stooges =
new ArrayList<>(asList("Larry", "Moe", "Curly", "Jo", "Blo"));
for (String stooge : stooges) { if ("Jo".equals(stooge)) {
*// no other stooge may be removed erroneously
* stooges.remove(stooge); *// erroneous removal, use iterator!
* } }
System.out.println(stooges); }
}
More information about the core-libs-dev
mailing list