Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsWhite Papers
Discussion GroupsFirst AidDatabasesJavaBeansGUIJava 3DVirtual MachineCORBASecurityToolsGeneral
Java DirectoryOpen Source ProjectsSample Book ChaptersUser GroupsWeb Resources
Related Topics
Databases.NETMore Topics ...

Java Forum / General / November 2006

Tip: Looking for answers? Try searching our database.

Modify collection inside iteration

Thread view: 
obaqueiro@gmail.com - 14 Nov 2006 12:13 GMT
Hello, I've got a question about the behaviour of Java:

I've got this code:

ArrayList<MyObject> objects = new ArrayList<MyObject>().
... (some code adding objects to array list)...
... some other code...

for (MyObject obj: this.objects) {
        if (obj.getFlag()==true){
                 objects.remove(obj);
        }

}

My main concern is what is the behaviour of the for(...) after removing

the obj from the objects list? is this a safe way to proceed? I need to

check all the objects in the list and then remove some of them if
certain condition is true. Usually I make it with for(int
i=0;i<objects.size();i++){...} and then after I remove the object I set

i to 0 (it might be possible just to avoid incrementing the counter).

But I want to know what is the behaivour of the iterator structure [
for(X:Y){} ] in these cases.

Is there any better way to achieve what I am trying to do?

Cheers.
Wallace - 14 Nov 2006 12:36 GMT
> Hello, I've got a question about the behaviour of Java:

Hello,

> [...]
> Is there any better way to achieve what I am trying to do?

you could create a new list
Chris Uppal - 14 Nov 2006 13:35 GMT
> My main concern is what is the behaviour of the for(...) after removing
> the obj from the objects list? is this a safe way to proceed?

You cannot, in general, safely add or remove objects from any kind of
Collection while you are iterating it (if you are lucky it'll thow a
ConcurrentModificationException, if you are unluckly it'll just malfunction
silently).  There is one exception (no pun intended), which is that most
Iterators are designed to allow modification of their underlying Collection
/via/ the iterator.  For instance, see java.util.ListIterator.remove().

The problem with that is that it requires an explicit iterator.  The for-loop
syntax is translated (by javac) into a use of an explicit iterator, but it
hides that iterator from you.  So, you cannot use the for-loop syntax if you
want to use remove().

Alternatively, you could build up a list of the elements you want to remove
during your for loop, and then remove them all after the loop has completed.

   -- chris
Red Orchid - 14 Nov 2006 14:22 GMT
obaqueiro@gmail.com wrote or quoted in
Message-ID: <1163506409.128952.11400@h54g2000cwb.googlegroups.com>:

>  for (MyObject obj: this.objects) {
>          if (obj.getFlag()==true){
>                   objects.remove(obj);
>          }
>
> }

The above code will throw 'ConcurrentModificationException'.

> check all the objects in the list and then remove some of them if
> certain condition is true. Usually I make it with for(int
[quoted text clipped - 6 lines]
>
> Is there any better way to achieve what I am trying to do?

If 'objects' is linked list (or array list of not large size),
the following code will be good.

<code_1>
Iterator<T> iter = objects.iterator();
       
while (iter.hasNext()) {
   if (...) {
       iter.remove();
   }       
}
</code_1>

But,
If 'objects' is array list of large size, I think that
'code_1' is not good.   Because copying internal
array is needed whenever 'iter.remove()' is called.

I think that the following code is better than 'code_1'.

<code_2>
List<T> res = new ArrayList<T>(objects.size());
       
for (T o : objects) {
   if (!(...)) {
       res.add(o);
   }
}

return res; // replace objects with res
</code_2>
Thomas Hawtin - 14 Nov 2006 16:12 GMT
> ArrayList<MyObject> objects = new ArrayList<MyObject>().
[...]
>  for (MyObject obj: this.objects) {
>          if (obj.getFlag()==true){
>                   objects.remove(obj);
>          }
>
> }

That may or may not throw ConcurrentModificationException (best efforts
doesn't mean the implementation tries that hard).

Some of your options, in descending order of merit, are:

private final List<MyObject> objects = new ArrayList<MyObject>();
...
   for (
       Iterator<MyObject> iter=this.objects.iterator();
       iter.hasNext();
   ) {
       if (obj.getFlag()) {
           iter.remove();
       }
   }

// Nice and exception-safe, but can't use final.
private List<MyObject> objects = new ArrayList<MyObject>();
...
   final List<MyObject> objectsLocal = new ArrayList<MyObject>();
   for (MyObject obj: this.objects) {
       if (!obj.getFlag()) {
           objectsLocal.add(obj);
       }
   }
   this.objects = objectsLocal;

// Full copy, but not even exception-safe.
private final List<MyObject> objects = new ArrayList<MyObject>();
...
   for (MyObject obj: new ArrayList(this.objects)) { // or toArray
       if (obj.getFlag()) {
           this.objects.remove(obj);
       }
   }

// Expensive writes, and even reads are more expensive.
private final List<MyObject> objects =
   new CopyOnWriteArrayList<MyObject>();
...
   for (MyObject obj: this.objects) {
       if (obj.getFlag()) {
           this.objects.remove(obj);
       }
   }

private final List<MyObject> objects = new ArrayList<MyObject>();
...
   final int num = this.objects.size();
   BitSet indexes = new BitSet(num);
   int index = 0;
   for (MyObject obj: this.objects) {
       if (obj.getFlag()) {
           indexes.set(index);
       }
       ++index;
   }
   for (int ct=num; --ct>= 0; ) {
       if (indexes.get()) {
           this.objects.remove(index);
       }
   }

private final List<MyObject> objects = new ArrayList<MyObject>();
...
   final List<Integer> indexes = new ArrayList<Integer>();
   int i = 0;
   for (MyObject obj: this.objects) {
       if (obj.getFlag()) {
           indexes.add(i);
       }
       ++i;
   }
   Collections.reverse(indexes);
   for (int index : indexes) {
       this.objects.remove(index);
   }

[ObDisclaimer: Not even compiled, let alone tested.]

Tom Hawtin


Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.