A vulnerability to the fast failure mechanism of ArrayList in Java--removing the second-to-last element with an iterator loop does not give an error

Source: Internet
Author: User
Tags concurrentmodificationexception

First, the problem description

Words not much to say, first on the code:

     Public Static voidMain (string[] args)throwsinterruptedexception {List<String> list =NewArraylist<string>();
List.add ("0th one"); List.add ("The first one"); List.add ("The second One"); List.add ("The third One"); List.add ("Fourth One"); for(String str:list) {if(Str.equals ("third") {System.out.println ("Delete:" +str); List.remove (str); }} System.out.println (list); }

It is possible to know that the fast failure mechanism will not be deleted directly in the Foreach Loop with the collection, and the iterator remove () method should be used. Otherwise it will error: Java.util.ConcurrentModificationException

But the actual output of this code is:

There is no error, this is why?

Second, the basic knowledge

The foreach and fast failure mechanisms of Java are introduced briefly:

foreach process:

When Java iterates through the collection list through foreach, the corresponding iterator is created for the list, and the Hasnext () function of the iterator is called to determine whether the next element is included, if any, call Iterator.next () to get the continuation traversal, and no to end the traversal.

Fast failure Mechanism:

Because of non-thread-safe, the next () method of the iterator is called when the modcount==expectedmodcount is judged, otherwise thrown concurrentmodificationexception. Modcount as long as the number of elements changes (Add,remove) is + 1, and the Add and remove methods of the collection and table do not update expectedmodcount, only the iterator remove resets expectedmodcount= Modcount, and move the cursor forward. So when iterating with iterators, you can only use iterator modifications.

Third, analysis

So by the above foreach introduction we can know that the above foreach Loop code can be written as follows:

         for (Iterator Iterator = list.iterator (); Iterator.hasnext ();) {            = (String) Iterator.next ();             if (Str.equals ("third")) {                System.out.println ("Delete:" + str);                List.remove (str);            }        }

The point is iterator.next () here, let's look at the source of next (): "The iterator here is ArrayList's private class, implements the iterator interface iterator, overrides various methods"

1          PublicE Next () {2 checkforcomodification ();3             Try {4                 inti =cursor;5E next =get (i);6Lastret =i;7cursor = i + 1;8                 returnNext;9}Catch(indexoutofboundsexception e) {Ten checkforcomodification (); One                 Throw Newnosuchelementexception (); A             } -}

Notice the 7th line! , that is, the cursor is at the very beginning of I, after calling next (), I return the first element, and then the next element is subscript, so the cursor is already the last element's subscript (size-1) when traversing to the penultimate element .

Watch out! when invoking a method of a collection or. Remove (int), the cursor is not changed , "action: After removing the element, call System.arraycopy to let the following element move forward one bit and release the last element bit", And this program at this time the size becomes the original size-1= 4, and the cursor is the original size-1=4, both equal! , and then look at the verdict Hasnext ():

         Public Boolean Hasnext () {            return cursor! = size ();        }

At this time cursor==size () ==4, the program thought that at this time has been traversed, so does not enter the loop, that is, will not enter into the next () method, there will be no checkforcomodification () judgment.

Iv. Verification

Our first sentence of the Foreach loop in the program gets the STR after adding a print, System.out.println (str);

So every time we enter the Foreach loop, we print 1, the rest is unchanged, we run it again, and the results are as follows:

Obviously, the fourth element has not been traversed, the analysis is correct , then if use Iterator.remove ()?

Then let's look at the source code of Iterator.remove (), "Iterator here is ArrayList's private class, implements the iterator interface iterator, overrides the various methods"

1          Public voidRemove () {2             if(Lastret < 0)3                 Throw Newillegalstateexception ();4 checkforcomodification ();5 6             Try {7Abstractlist. This. Remove (Lastret);8                 if(Lastret <cursor)9cursor--;TenLastret =-1; OneExpectedmodcount =Modcount; A}Catch(indexoutofboundsexception e) { -                 Throw Newconcurrentmodificationexception (); -             } the}

Looking at line 7th, the internal is actually the call to the list of the Remove (int) method, but different places to note:

Line 9th: cursor--, that is, after deleting the current element, he put the moved pointer back to the current element subscript, so the continuation loop will not skip the current element bit of the new value;

Line 11th: Expectedmodcount = modcount; Update the Expectedmodcount so that the two are the same, and the error will not be detected by checkforcomodification () in the continuation loop.

V. Conclusion

1. Each time the Foreach Loop starts , the next () method causes the cursor to change to the next element subscript;

2. When the Remove () method of ArrayList is finished, the next element moves to the position of the deleted element, and by 1, the cursor points at this point to the next next element in the original deleted element, where the foreach Loop continues, The next element of the deleted element is not traversed ;

3. The Checkforcomodification () method is used to determine the fast failure mechanism, which in the Iterator.next () method must not be called until it enters the Foreach loop;

4. By 2, when the ArrayList remove () method continues the Foreach loop when foreach deletes the second-to-last element, the penultimate element is skipped to exit the loop , and the Union 3 is known to delete the second-to-last element, Does not go into the judgment of a fast-failing mechanism.

5. The Iterator.remove () method will put the cursor back in the correct position after deleting and moving the element, without causing the element to skip over, and updating the expectedmodcount is a safe choice.

A vulnerability to the fast failure mechanism of ArrayList in Java--removing the second-to-last element with an iterator loop does not give an error

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.