The Java Iterator Upgrade edition explores

Source: Internet
Author: User
Tags concurrentmodificationexception

Alei recently and iterators more on the strength, before thought to delve into the iterator, not Chengxiang originally is sit idle, Ishine. What's the above-mentioned thing? But to mend, not late also, after my many experiments, finally understand some of the ingenious mechanism, gossip less, we get to the point.

Note that all knowledge points are then explained in detail using the ArrayList container class as an example.

Before we talk about this, we need to focus on two member variables first:

1. The ArrayList class inherits the member variable modcount of the Abstractlist class:

protected transient int modcount = 0;

2. The member variable Expectedmodcount in the private inner class Itr of the ArrayList class:

int expectedmodcount = Modcount;

Then look at the ITR class Source:

Private classItrImplementsIterator<e> {    intCursor//index of next element to return    intLastret =-1;//index of last element returned;-1 if no such    intExpectedmodcount =Modcount;  Public BooleanHasnext () {returnCursor! =size; } @SuppressWarnings ("Unchecked")     PublicE Next () {checkforcomodification (); inti =cursor; if(I >=size)Throw Newnosuchelementexception (); Object[] Elementdata= ArrayList. This. Elementdata; if(I >=elementdata.length)Throw Newconcurrentmodificationexception (); Cursor= i + 1; return(E) Elementdata[lastret =i]; }     Public voidRemove () {if(Lastret < 0)            Throw Newillegalstateexception ();        Checkforcomodification (); Try{ArrayList. This. Remove (Lastret); Cursor=Lastret; Lastret=-1; Expectedmodcount=Modcount; } Catch(Indexoutofboundsexception ex) {Throw Newconcurrentmodificationexception (); }} @Override @SuppressWarnings ("Unchecked")     Public voidForeachremaining (consumer<?SuperE>consumer)        {Objects.requirenonnull (consumer); Final intSize = ArrayList. This. Size; inti =cursor; if(I >=size) {            return; }        Finalobject[] Elementdata = ArrayList. This. Elementdata; if(I >=elementdata.length) {Throw Newconcurrentmodificationexception (); }         while(I! = size && Modcount = =Expectedmodcount) {consumer.accept ((E) elementdata[i++]); }        //update once at end of iteration to reduce heap write trafficcursor =i; Lastret= I-1;    Checkforcomodification (); }    Final voidcheckforcomodification () {if(Modcount! =expectedmodcount)Throw Newconcurrentmodificationexception (); }}

When we use the iterator () method of the ArrayList container, a specific iterator object is created in the stack space, and the value of the member variable Modcount is assigned to the member variable Expectedmodcount. Know this interesting thing can stop first, let us look at the ArrayList class remove () method of the source code:

The parameter is a remove () of type int:

 Public E Remove (int  index) {    Rangecheck (index);    Modcount++    ; = Elementdata (index);     int nummoved = size-index-1;     if (nummoved > 0)        System.arraycopy (elementdata, index+1, Elementdata, index,                         nummoved);    elementdata[null//  clearto let GC do it work    return  OldValue;}

The parameter is a remove () of type Object:

 Public BooleanRemove (Object o) {if(O = =NULL) {         for(intindex = 0; index < size; index++)            if(Elementdata[index] = =NULL) {fastremove (index); return true; }    } Else {         for(intindex = 0; index < size; index++)            if(O.equals (Elementdata[index])) {fastremove (index); return true; }    }    return false;}/** Private Remove method that skips bounds checking and does not * return the value removed.*/Private voidFastremove (intindex) {Modcount++; intnummoved = size-index-1; if(nummoved > 0) system.arraycopy (elementdata, index+1, Elementdata, Index, nummoved); elementdata[--size] =NULL;//clear to let GC do it work}

Take the ArrayList class remove () method as an example, as long as we call this method once, then Modcount will add 1. So we can understand that Modcount is a variable that records the number of changes to a container object, which is a counter. Small partner door can go to check the source, not only remove (), all involved in the ArrayList object of the increase, deletion, modification of any method, when we call such a method, then the Modcount will be added 1, that is, the change of the container object is recorded once. For example, when I create a ArrayList object, AL, I call Al.add () once, call Al.remove () once, and then call Al.add () once, then Modcount = 3, which shows that Al was modified 3 times.

Any additions or deletions to the container object before the iterator object is created will only let Modcount, when we create an iterator object corresponding to the container class, int expectedmodcount = Modcount, the iterator object The Expectedmodcount member variable is initialized to the same value as the value in Modcount.

With iterators, and then iterating with iterators, it involves the hasnext () of the Iterator object, and the next () method, we look at the source code of the two methods:

 Public BooleanHasnext () {returnCursor! =size;} @SuppressWarnings ("Unchecked") PublicE Next () {checkforcomodification (); inti =cursor; if(I >=size)Throw Newnosuchelementexception (); Object[] Elementdata= ArrayList. This. Elementdata; if(I >=elementdata.length)Throw Newconcurrentmodificationexception (); Cursor= i + 1; return(E) Elementdata[lastret =i];}

Thus, two methods will not change the value of Expectedmodcount, how to understand expectedmodcount this member variable? Look again at the Remove () method in the iterator source code:

 Public voidRemove () {if(Lastret < 0)        Throw Newillegalstateexception ();    Checkforcomodification (); Try{ArrayList. This. Remove (Lastret); Cursor=Lastret; Lastret=-1; Expectedmodcount=Modcount; } Catch(Indexoutofboundsexception ex) {Throw Newconcurrentmodificationexception (); }}

In the method body of the Remove () method, there is "expectedmodcount = Modcount; "Such a line of statements, no matter how many times we call the Remove () method of the iterator, always let the value of Expectedmodcount equal to Modcount, where the expectedmodcount can be understood as using iterators to modify the Container class object" Expected number of changes ", that is, the" expected number of changes in the iterator "must be the same as the number of changes in the container has been recorded modcount, then when you iterate through the container class object through the iterator and modify, using the iterator itself, remove () is meaningful (that is, let Expectedmodcount = modcount)!! The Checkforcomodification () method in the first line of the next () method is defined like this:

Final void checkforcomodification () {    if (modcount! = expectedmodcount        )throw  New  concurrentmodificationexception ();}

Read the source code, we should know: the role of Checkforcomodification () is to check whether the values of Expectedmodcount and modcount are equal, if not equal, throw Concurrentmodificationexception this exception. It is obvious that when we traverse through an iterator, if we use any method of modifying the Container class object provided by the non-iterator object, then the value of the modcount increases, and the Expectedmodcount value does not change, then the next loop, the next () The Checkforcomodification () method in the first line of the method body checks to Expectedmodcount and Modcount and throws concurrentmodificationexception.

So, when iterating through iterators, any element in the container object cannot be changed or deleted by the method provided by the container class? Not also, Alei left such a piece of code:

 Public Static voidMain (string[] args) {Collection C=NewArrayList (); C.add (NewString ("AAA")); C.add (NewString ("BBB")); C.add (NewString ("CCC")); C.add (NewString ("ddd")); C.add (NewString ("FFF")); C.add (NewString ("Eee"));  for(Object o:c) {//System.out.print (o + "");        if(O.equals ("FFF") {c.remove (o); }} System.out.println (c);}

When we run this program, you will find out how the string object "FFF" was successfully deleted?! This is where I have been puzzled and slightly idiot. In fact, I can conclude that when iterating through an iterator, the second-to-last element in the container object must be removed (regardless of how large the container's size is) by the Remove () method provided by the container class. Why is that? Haha, for this problem, let the small partners to solve their own ^_^!

The Java Iterator Upgrade edition explores

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.