I am removing elements from an ArrayList, consider the code below :
private static List<Person> persons = new ArrayList<>();
//initialize the persons arraylist.
for (Person p : persons) {
if (p.getAge() < 18) {
persons.remove(p);
}
}
The initialize method:
private static void initialize() {
persons.add(new Person("Rahul", 25, Gender.MALE, Citizenship.INDIA));
persons.add(new Person("Sally", 21, Gender.FEMALE, Citizenship.USA));
persons.add(new Person("Ben", 35, Gender.MALE, Citizenship.CANADA));
persons.add(new Person("Wayne", 30, Gender.MALE, Citizenship.UK));
persons.add(new Person("ShaneYoung", 18, Gender.MALE, Citizenship.AUSTRALIA));
persons.add(new Person("Kimmo", 17, Gender.MALE, Citizenship.FINLAND));
persons.add(new Person("Simo", 17, Gender.MALE, Citizenship.FINLAND));
}
Output: [Rahul, Sally, Ben, Wayne, ShaneYoung, Simo]
Notice that the 2nd last and last items should not be returned ideally. I understand that if we try to modify the structure of the ArrayList while iterating through it , we could get a ConcurrentModificationException. I am referring to the remove(Object o) in the ArrayList. This is of course not the recommended way of removing the elements while iterating.The exception is thrown in most cases. However if I were to have a list where the 2nd last item satisfies my removal condition and the last one also satisfies the removal condition, a ConcurrentModificationException is not thrown because hasNext method returns false. The code for the hasNext() is:
return cursor != size
In this scenario, cursor == size. But note that that last element is also skipped or not processed.So no exception but the last element is skipped but also returned in the output.
I have gone through this bug and also looked at duplicate bugs it is linked to. They seem to highlight a slightly different scenario.
When we call the Iterator.remove, it seems to adjust the cursor position to lastRet. So using an Iterator.remove even with a 2nd last and last item which satisfies the removal condition works fine but the remove(Object o) which in turn calls the fastRemove does not seem to set this and hence skips the last element altogether.
I know the Iterator.remove javadoc mentions about unspecified behavior, the comments mentioned in the bugs raised above also indicate that the ConcurrentModificationException is thrown as a best effort. But considering the code above, the part where the last element is not filtered out, isn't this a bug or a scenario which should be handled in a better way ?
I have noticed another question here but the answers only explain about how the output is achieved given the current implementation which I have mentioned above.My question is more about whether the hasNext implementation should be changed to handle this scenario ?