Removing object from arraylist when pointed to by iterator

  • Thread starter nooneinparticular314159
  • Start date
N

nooneinparticular314159

I have an arraylist of objects of a certain type. I use an iterator
on that arraylist to get the next instance of the object, using the
iterator.next() method. But if I succeed in performing an operation
on the object, I want to remove the object from my arraylist. The
question is how I remove it without calling .next() again, since that
will remove the next one, not the current one? ie. If I am currently
working on the object at position 4 in the arraylist (through the
iterator), I want to remove the object at position 4. But I don't
know what position the object is in because I got it through the
iterator.

Thanks!
 
A

Arne Vajhøj

I have an arraylist of objects of a certain type. I use an iterator
on that arraylist to get the next instance of the object, using the
iterator.next() method. But if I succeed in performing an operation
on the object, I want to remove the object from my arraylist. The
question is how I remove it without calling .next() again, since that
will remove the next one, not the current one? ie. If I am currently
working on the object at position 4 in the arraylist (through the
iterator), I want to remove the object at position 4. But I don't
know what position the object is in because I got it through the
iterator.

Save a ref to what next() returns.

And I am pretty sure that the ArrayList iterator does not like
you calling remove while iterating.

Arne
 
S

softwarepearls_com

I have an arraylist of objects of a certain type.  I use an iterator
on that arraylist to get the next instance of the object, using the
iterator.next() method.  But if I succeed in performing an operation
on the object, I want to remove the object from my arraylist.  The
question is how I remove it without calling .next() again, since that
will remove the next one, not the current one?  ie.  If I am currently
working on the object at position 4 in the arraylist (through the
iterator), I want to remove the object at position 4.  But I don't
know what position the object is in because I got it through the
iterator.

I would say you're caught in the iterator "routine" so many fall prey
to... you should not be using an iterator when working with an
ArrayList ! You should be iterating the "old fashioned" way ... using
direct get(int) .. these don't entertain the concept of
ConcurrentModificationException. It's faster too.
 
M

Mike Schilling

I have an arraylist of objects of a certain type. I use an iterator
on that arraylist to get the next instance of the object, using the
iterator.next() method. But if I succeed in performing an operation
on the object, I want to remove the object from my arraylist. The
question is how I remove it without calling .next() again, since
that
will remove the next one, not the current one? ie. If I am
currently
working on the object at position 4 in the arraylist (through the
iterator), I want to remove the object at position 4. But I don't
know what position the object is in because I got it through the
iterator.


If you call remove() on the iterator, you'll remove the last one
fetched. That is, code like

ArrayList<MyType> list;
for (Iterator<MyType> iter = list.iterator(); iter.hasNext(); )
{
MyType obj = list.next();
if (shouldBeRemoved(obj))
iter.remove();
}

does what you want.
 
D

Donkey Hottie

I would say you're caught in the iterator "routine" so many fall prey
to... you should not be using an iterator when working with an
ArrayList ! You should be iterating the "old fashioned" way ... using
direct get(int) .. these don't entertain the concept of
ConcurrentModificationException. It's faster too.

If one wants to iterate thru the ArrayList, and remove items here and
there, I'd say an Iterator is much simpler and safer to use.

Iterating with an index may cause undesired results, as shown by the
following example.

package itertest;

import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;

public class Main
{
public static void main(String[] args)
{
final int SIZE=1000;
List list = new ArrayList(SIZE) ;

for (int i=0; i < SIZE; i++)
{
list.add(Integer.toString(i));
}

for (int i=0; i < list.size(); i++)
{
String s = (String) list.get(i) ;
System.out.println("list.get(" + i + ") (list.size=" +
list.size() + ") = " + s) ;
list.remove(i) ;
}

list = new ArrayList(SIZE) ;

for (int i=0; i < SIZE; i++)
{
list.add(Integer.toString(i));
}

for (Iterator i=list.iterator(); i.hasNext(); )
{
String s = (String) i.next() ;
System.out.println("i.next() = " + s) ;
i.remove();
}
}
}


The list will never get iterated thru by using get() ! The algorighm
using that requires something more, which makes it more complicated.
 
D

Daniel Pitts

I have an arraylist of objects of a certain type. I use an iterator
on that arraylist to get the next instance of the object, using the
iterator.next() method. But if I succeed in performing an operation
on the object, I want to remove the object from my arraylist. The
question is how I remove it without calling .next() again, since that
will remove the next one, not the current one? ie. If I am currently
working on the object at position 4 in the arraylist (through the
iterator), I want to remove the object at position 4. But I don't
know what position the object is in because I got it through the
iterator.

Thanks!
it.remove(); will remove the object that was last returned by it.next()
 
D

Daniel Pitts

softwarepearls_com said:
I would say you're caught in the iterator "routine" so many fall prey
to... you should not be using an iterator when working with an
ArrayList ! You should be iterating the "old fashioned" way ... using
direct get(int) .. these don't entertain the concept of
ConcurrentModificationException. It's faster too.
Lies!

You don't see the concurrent modification errors, but they still can
cause bugs in your code!
Also, It isn't necessarily faster. I would assume its "about the same"
for the average program, but the benefits of using an iterator far
outweigh the cost for the average program. Fewer bugs, bugs caught
sooner, etc...
 
M

Mike Schilling

Daniel said:
Lies!

You don't see the concurrent modification errors, but they still can
cause bugs in your code!
Also, It isn't necessarily faster. I would assume its "about the
same" for the average program, but the benefits of using an iterator
far outweigh the cost for the average program. Fewer bugs, bugs
caught sooner, etc...

And it's easier to get right. Iterator.remove() does what the OP
wants. The equivalent with integer indices is:

for (int i = 0; i < list.length(); i++)
{
if (shouldRemove(list.get(i))
{
list.remove(i);
i--; // Needed to avoid skipping a list member.
// Or is it?
}
}

And, when iterating the other way:

for (int i = list.length()-1; i >= 0; i--)
{
if (shouldRemove(list.get(i))
{
list.remove(i);
i++; // Needed to avoid skipping a list member.
// Or is it?
}
}

The answers are "yes" and "no" respectively, but why take the chance
of getting it wrong?
 
J

jolz

Instead of calling iterator.remove() for every object you remove you can:
- remember all object that you want to keep in a temporary list
- after loop is finished clear original list and insert to it content of
the temporary list (or switch references if it isn't used anywherere
else in the code)
Above makes no sense if you have 5 objects in the list, but with many
objects often removed from an ArrayList you will notice that calling
iterator.remove() slows down your application.
Or you can use LinkedList instead of ArrayList if you allways use
iterators - obiously code with a single call iterator.remove(); is
simpler and removing from LinkedList is way faster thar removing from
ArrayList.
 
T

Tom Anderson

I would say you're caught in the iterator "routine" so many fall prey
to... you should not be using an iterator when working with an ArrayList
! You should be iterating the "old fashioned" way ... using direct
get(int) .. these don't entertain the concept of
ConcurrentModificationException. It's faster too.

No. I mean, this is just really terrible advice. Please don't ever give
anyone advice again. You're really not helping.

tom
 
P

Paul Tomblin

In a previous article said:
No. I mean, this is just really terrible advice. Please don't ever give
anyone advice again. You're really not helping.

What he said.

There is no way in hell that using "get" is faster than an iterator. And
maybe you won't see a ConcurrentModificationException, but that's because
doing it that way won't notice the bugs you've introduced by concurrent
modifications.
 
L

Lasse Reichstein Nielsen

(e-mail address removed) (Paul Tomblin) writes:

[About ArrayList]
There is no way in hell that using "get" is faster than an iterator.

Since ArrayList inherits its iterator from AbstractList, which says:
---
* Unlike the other abstract collection implementations, the programmer does
* <i>not</i> have to provide an iterator implementation; the iterator and
* list iterator are implemented by this class, on top the "random access"
* methods: <tt>get(int index)</tt>, <tt>set(int index, Object element)</tt>,
* <tt>set(int index, Object element)</tt>, <tt>add(int index, Object
* element)</tt> and <tt>remove(int index)</tt>.<p>
---
it would indeed be odd if the iterator is slower. It can, at best, be
as fast as using "get", and it has its own overhead too (e.g., its
index is stored in a field on the iterator, where a loop using "get"
could use a local variable).
Whether the overhead is significant, or it is optimized away by
the runtime system, only profiling can say.
And maybe you won't see a ConcurrentModificationException, but
that's because doing it that way won't notice the bugs you've
introduced by concurrent modifications.

That is correct, except in the case where you know, and I mean
*absolutely* know, that the list is only *ever* used in a single
thread.


/L
 
D

Daniel Pitts

Lasse said:
That is correct, except in the case where you know, and I mean
*absolutely* know, that the list is only *ever* used in a single
thread.
Concurrent modification bugs do not require multiple threads to appear.
As a matter of fact, I've run into them most often in programs where
only one thread has access to the collection in question. Algorithms
like the following can lead to the bug:

1. Go through all SimulationObjects
2. execute doSomething on each object.

where the some SimulationObject instance have a doSomething that can
affect the list of all simulation objects. Such as a robot firing a
missile (addition), or a missile exploding and killing a robot
(removal). In that case, I might never have noticed the bug if I was
using get. As it turns out, the "best" way around that bug in my code
was to create a two lists "toBeRemoved" and "toBeAdded", and handle that
after the main loop.

So, the point remains, use Iterator, and if you get CME don't assume its
a synchronization/threading issue (although it might me).
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,756
Messages
2,569,535
Members
45,008
Latest member
obedient dusk

Latest Threads

Top