I have an object that is in an arraylist, called a PowerUp. I want these to be clickable, and when they are clicked, they will be removed from the screen, and ultimately taken out of the arraylist. I have inserted the handler into the class HealthPack, which in turn extends PowerUp. I am trying to access the certain HealthPack that was clicked on and remove it from that list. I keep getting either it not working correctly, or a ConcurrentModificationException. Here is my code I am trying to work with:
for (int i = 0; i < ((SurvivalMode) m).getPowerUps().size(); i++) {
PowerUp p = ((SurvivalMode) m).getPowerUps().get(i);
if (p.equals(hp)) { // HealthPack hp = this;
((SurvivalMode) m).getPowerUps().remove(p);
addPoints();
}
}
This current code actually throws a ConcurrentModificationException when I go to click on a HealthPack when the list is both adding it, and another is iterating through it. I have tried synchronizing the methods that mess with the list, but it didn't help.
How would I keep my program from throwing a ConcurrentModificationException if one method is trying to remove an element from the list while another one is either iterating through the list or one is adding or removing an element from the list?
EDIT:
Here is some additional code that actually modifies the arraylist for the items:
if (powerups.size() >= 15 || isPaused()) return;
int gen = random.nextInt(10);
if (gen == 0) {
powerups.add(new HealthPack(this));
addMouseListener(powerups.get(powerups.size() - 1).getMouseListener());
}
}
and some code that actually iterates through that list (which throws the ConcurrentModificationException):
for (PowerUp p : powerups) p.update();
CURRENT METHOD:
Here is the current method that I have attempted to remove from the list on click, but it still doesn't work so well, as in it doesn't remove anything at all or it will remove the wrong one, and sometimes even calls the method for all of the other PowerUps in the list:
Iterator<PowerUp> iter = ((SurvivalMode) m).getPowerUps().iterator();
while (iter.hasNext()) {
PowerUp p = (HealthPack) iter.next();
if (p.equals(hp)) {
((SurvivalMode) m).getPowerUps().remove(p);
}
CellDefender.getSounds().play(SoundType.HEALTH_PACK);
break;
}
Update 2:
What I have recently done is actually copy the array list within another point, and it partially helps to reduce the errors (within my update method):
CopyOnWriteArrayList<PowerUp> cpowerups = new CopyOnWriteArrayList<PowerUp>();
for (int i = 0; i < powerups.size(); i++) {
cpowerups.add(powerups.get(i));
}
for (PowerUp p : cpowerups) p.update();
And I would like to ask one thing, is there a way to detect if a list is currently being modified, and if the list is being modified to break out of the loop?
You have to use Iterator for loop to remove elements from ArrayList.
Iterator<PowerUp> iter = ((SurvivalMode) m).getPowerUps().iterator();
while(iter.hasNext()) {
PowerUp p = iter.next();
// your conditions to remove element here
iter.remove();
}
Since I don't know your entire code, I have to make some assumptions.
My first assumption is, that your problematic code fragment is called somehow by the update method of the PowerUp class.
As stated in [1], a for each loop uses an Iterator object to iterate over the elements of an ArrayList.
Those Iterator objects returned by an ArrayList are fail-fast.
That is, their methods throw a ConcurrentModificationException if the ArrayList is modified in any way after the creation of such an Iterator object, except through the object itself. (cf. [2])
If my assumption is correct, your code for (PowerUp p : powerups) p.update(); creates such an Iterator object and modifies the ArrayList within the other given code fragment.
That is the reason why you encounter the same exception with the code proposed by Alex.
A solution of your problem is the use of a CopyOnWriteArrayList whenever you iterate over a Collection (ArrayList, LinkedList, etc.) It creates a shallow copy of the collection and iterates over the elements of the copy, so that you can modify the original collection without the occurrence of a ConcurrentModificationException.
That means, you have to replace for (PowerUp p : powerups) p.update(); with for (PowerUp p : CopyOnWriteArrayList(powerups) p.update(); and use
Iterator<PowerUp> iter = ((SurvivalMode) m).getPowerUps().iterator();
while(iter.hasNext()) {
PowerUp p = iter.next();
// your conditions to remove element here
iter.remove();
}
as proposed by Alex.
Related
I am passing Arraylist of ParseObject, and then i am putting one one foreach loop to extract the items with a condition when user object is not equals to null. There are two problems which i am facing.
1. If i am doing the following lines of code by passing different data to another list and then pass that list in my adapter, i am getting random data with numbers for example: If on item # 1 the name is "MAC" then it is showing in item 3.
ArrayList<ParseObject> checkRequestedNetArrayList = new ArrayList<ParseObject>();
requestedNetArrayList = (ArrayList<ParseObject>) objects;
MyResponsibilitesActivity.requestedNetArrayList = requestedNetArrayList;
adapterRequest = new GenericAdapter<ParseObject>(
getApplicationContext(),
requestedNetArrayList,
R.layout.requested_trust_net_list_item,
requestedDataBinder);
requestListView.setAdapter(adapterRequest);
requestedNetArrayList = (ArrayList<ParseObject>) objects;
for(ParseObject object: objects){
System.out.println(object);
object.getParseObject("user");
if(object.has("user")){
checkRequestedNetArrayList.add(object);
}else{
checkRequestedNetArrayList.remove(object);
}
}
adapterRequest = new GenericAdapter<ParseObject>(
getApplicationContext(),
checkRequestedNetArrayList,
R.layout.requested_trust_net_list_item,
requestedDataBinder);
requestListView.setAdapter(adapterRequest);
If i am doing the following line of code to just direct giving the items in the same list, i am getting the java.util.ConcurrentModificationException
for(ParseObject object: objects){
if(object.has("user")){
requestedNetArrayList.add(object);
}
}
else{
requestedNetArrayList.remove(object);
}
adapterRequest = new GenericAdapter<ParseObject>(
getApplicationContext(),
requestedNetArrayList,
R.layout.requested_trust_net_list_item,
requestedDataBinder);
requestListView.setAdapter(adapterRequest);
}
Please help me out here.
You can not remove an element from list while accessing it.
You have to use Iterator.
Where ever you are removing the object, use it.remove();
Iterator<ParseObject> it = objects.iterator();
while(it.hasNext()){
Object object = it.next();
//your stuff
it.remove();
}
I think you might want to check this article about deep copy also.
UPDATE
Since you want to add elements to the list it is not directly possible with iterator. Now you are facing problem because you are directly assigning objects to requestedNetArrayList instead of that do it in the following way :
ArrayList<ParseObject> requestedNetArrayList = new ArrayList<>(objects);
Then iterate over objects as you are doing now, and remove from or add to
requestedNetArrayList (which you are pretty much already doing).
When you make iteration using for-each construction for Collection
for (Object x : collection) ...
you have implicit creation of Iterator object for that Collection. This iterator performs a check: is collection was changed since iterator was created? If so, throwing an exception. So, you should avoid to any modify to your collection, until iterator done. That means, you should not use add and remove.
In either way, it is better to access ArrayList by index, because it will prevent creation of Iterator object. Like this:
for (int i = objects.size() - 1; i >= 0; i--) {
ParseObject object = objects.get(i);
// when iterating from tail to head, you can safely add or remove objects to/from this array list
}
Instead of assigning the reference of objects to requestedNetArrayList,
create a new ArrayList with the same contents
requestedNetArrayList=new ArrayList<ParseObject>(objects);
Then you can iterate on objects and modify requestedNetArrayList.
I have a very basic question.
I have created simple ArrayList and I am removing the item while iterating using for-each loop. It gives me java.util.ConcurrentModificationException because I can't remove an item while iterating but when I un-comment the if condition it works fine.
Please can anybody explain me how for-each works in this way.
ArrayList<String> list1 = new ArrayList<String>();
list1.add("Hello");
list1.add("World");
list1.add("Good Evening");
for (String s : list1) {
//if (s.equals("World")) {
list1.remove(1);
//}
}
If I change it to list1.remove(2); or list1.remove(0); then also its working fine.
Note: This is sample code and I know it will work fine using Iterator. My sole purpose of this question is to know how method remove() works perfectly if condition is un-commented no matter what index you are removing from the list.
The list has a variable called modCount, which means "modification count". Whenever you call remove (or perform other structural modifications), it increments the modCount.
The iterator can't keep track of its position in the list if you are adding or removing elements without telling the iterator. So as a safety check, at the start of iteration, the iterator makes a note of the modCount, saving it as expectedModCount. When each item is read from the iterator, the iterator checks to make sure the modCount still equals the expected value, and throws an exception if it doesn't.
Usually, this will successfully cause the exception to be thrown if the list is unsafely modified during iteration. However, it's not sufficient in this case when the if statement is enabled. After your code has read "World", that item is removed, and so the list now contains ["Hello", Good Evening"]. The iterator is still at position 1 (which now contains "Good Evening") and when it tries to read the next item, it finds it has now reached the end of the list, so it doesn't bother to check the modCount. Hence, no exception.
Note the caveat in the ConcurrentModificationException documentation: "It is, generally speaking, impossible to make any hard guarantees in the presence of unsynchronized concurrent modification. Fail-fast operations throw ConcurrentModificationException on a best-effort basis."
Even if it doesn't happen to throw the exception in this case, the code is still wrong. To remove an element while iterating, you must use the iterator's own remove method:
for (Iterator<String> it = list1.iterator(); it.hasNext();) {
String s = it.next();
if (s.equals("World")) {
it.remove();
}
}
That way, the iterator knows that the list has changed and can still iterate correctly.
Alternatively, you can iterate from a temporary copy of the list:
for (String s : new ArrayList<>(list1)) {
if (s.equals("World")) {
list1.remove(...);
}
}
Although, in this simple case, you don't even need to do that; you can just write:
list1.remove("World");
You can also use an index-based removal. The drawback of this solution is that the list1.size() gets evaluated during every loop iteration. The positive thing is that removing an item from a List by its index is faster.
for (int i = 0; i < list1.size(); /* i incremented in loop body */) {
if ("World".equals(list1.get(i))) {
list1.remove(i);
}
else {
i++;
}
}
Use an Iterator and call remove():
Iterator<String> iter = list1.iterator();
while (iter.hasNext()) {
String str = iter.next();
if (someCondition)
iter.remove();
}
ATTENTION: I CANNOT know if doSomething will remove the element or not. This is an exceptional case that my data structure needs to handle.
My problem is simples:
int size = list.size();
for(int i = 0; i < size; i++) {
MyObj mo = list.get(i);
mo.doSomething();
}
Now if doSomething() remove mo from the list, I eventually get an ArrayIndexOutOfBounds because the list has now shrunk.
What data structure should I use to allow iteration with the possibility of removing? I can NOT use an iterator here, in other words, I can NOT make doSomething return a boolean and call iterator.remove(). The data structure has to somehow handle the situation and continue to iterator through the rest of the elements still there.
EDIT: I CANNOT know if doSomething will remove the element or not. This is an exceptional case that my data structure needs to handle.
Part II => Making a smart listeners notifier to avoid code duplication everywhere
You can use an ArrayList, for example, as long as you update the index and size when something is removed.
List<MyObj> list = new ArrayList<MyObj>();
int size = list.size();
for(int i = 0; i < size; i++) {
MyObj mo = list.get(i);
mo.doSomething();
if (size > list.size()) {
size = list.size();
i--;
}
}
This only works if the item removed is the last one examined. For other changes to the list you will have to have more complicated logic.
What data structure should I use to allow iteration with the possibility of removing?
The simplest option is to take a copy of the list and iterate over that instead:
List<MyObj> copy = new ArrayList<MyObj>(list);
for (MyObj mo : copy) {
mo.doSomething();
}
Now it doesn't matter whether or not anything removes an idea from the original list - that won't change the copy of the list.
Another option is to use CopyOnWriteArrayList. You can then just iterate and remove or add items at will:
The "snapshot" style iterator method uses a reference to the state of the array at the point that the iterator was created. This array never changes during the lifetime of the iterator, so interference is impossible and the iterator is guaranteed not to throw ConcurrentModificationException. The iterator will not reflect additions, removals, or changes to the list since the iterator was created.
I think you should change you doSomething(). If mo.doSomething() can remove mo from l, you mo must know your l.
You can change the code like this:
Create a valid flag, inside of your MyObj. Only listen if valid.
while(list.hasNext()) {
MyObj mo = list.next()
if(mo.isValid()){
mo.doSomething();
} else {
list.remove();
}
}
I'm iterating a java.util.LinkedList and in some cases I add an element to it.
LinkedList<Schedule> queue = new LinkedList<Schedule>(schedules);
ListIterator<Schedule> iterator = queue.listIterator();
while (iterator.hasNext()) {
Schedule schedule = iterator.next();
if(condition)
iterator.add(new Schedule());
}
The problem is that if I start for example with one item, the new item is added before the next iterator.next() call and the iteration exits.
How can I append the item at the end of the LinkedList while iterating?
Please don't tell me to use another list and iterate it after the first because it doesn't solve my problem correctly.
Assuming you don't have a hard requirement to use an iterator then you can just shelve it and 'iterate' over the list by index instead:
LinkedList<Schedule> list;
for (int i = 0; i < list.size(); i++) {
final Schedule schedule = list.get(i);
if(condition)
list.add(new Schedule());
}
If you cannot use another list, you could solve your problem by keeping a count of the number of elements you processed via the iterator and compare that to the original size of the list: all new element will be at the end of the list, so you can end your loop when you have reached the original size.
LinkedList<Schedule> queue = new LinkedList<Schedule>(schedules);
int origSize = queue.size();
int currCount = 0;
ListIterator<Schedule> iterator = queue.listIterator();
while (iterator.hasNext()) {
++currCount;
if (currCount >= origSize) {
break; // reached the end of the original collection
}
Schedule schedule = iterator.next();
if(condition)
iterator.add(new Schedule());
}
You could also use an extra list to keep track of the new elements and add that to the original list after the processing is over:
LinkedList<Schedule> queue = new LinkedList<Schedule>(schedules);
LinkedList<Schedule> addQueue = new LinkedList<Schedule>();
ListIterator<Schedule> iterator = queue.listIterator();
while (iterator.hasNext()) {
Schedule schedule = iterator.next();
if(condition)
addQueue.add(new Schedule());
}
queue.addAll(addQueue);
Also, note that iterator.add()
Inserts the specified element into the list (optional operation). The element is inserted immediately before the next element that would be returned by next, if any, and after the next element that would be returned by previous, if any. (If the list contains no elements, the new element becomes the sole element on the list.) The new element is inserted before the implicit cursor: a subsequent call to next would be unaffected, and a subsequent call to previous would return the new element. (This call increases by one the value that would be returned by a call to nextIndex or previousIndex.)
so if you have more than one elements in the list, it will not add the new ones to the end, but between the current one and the one returned by next(). If you indeed want to place the new elements at the end of the list, use queue.add(...)
In general, it is not advisable to modify a collection while traversing it via an iterator, so I suggest you use the second approach (collect the extra elements in a separate list and add them to the original at the end)
As others have suggested, there is no efficient, off-the-shelf support for end-insertion during iteration in the current Collections framework. One suggestion involved rewriting the iterator. But I say, why not go a couple steps further?
Use reflection to modify the accessibility of the Node class, which gives you references to the double links, so you don't need to start iteration over with get(index), which should not be used in performant code.
Inherit/derive from LinkedList and override judiciously.
This is a no-brainer, but in the same spirit as 2 above, since the JDK is open-source, borrow the source as needed and write your own implementation.
In either case, I really feel this feature should be provided by Java LinkedList API.
How can I append the item at the end of the LinkedList while
iterating?
public void addWork(Scheduler scheduler)
{
synchronized(scheduler)
{
queue.addLast(scheduler);
}
}
and you can use queue.removeFirst() to deal with item in the queue from top-to-down.
public synchronized Scheduler getWork()
{
return queue.removeFirst();
}
Edited.
The requirements to add while iterating and include the added items in the iteration can only be met if you don't use an iterator for iteration since there is no way to recompute the state of your iterator every time an element is added. If you accept the less efficient get method to do your iteration, the problem is trivial. For example
LinkedList<Schedule> queue = new LinkedList<Schedule>(){{add(new Schedule());add(new Schedule());add(new Schedule());}};
int i = 0;
// queue.size() is evaluated every iteration
while (i < queue.size()) {
Schedule schedule = queue.get(i);
if(i++ % 2 == 0)
queue.add(new Schedule());
}
System.out.println(queue.size());
prints 6 as expected.
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Java: adding elements to a collection during iteration
My problem is that I want to expand a list with new elements while iterating over it and I want the iterator to continue with the elements that I just added.
From my understanding the ListIterator.add() adds an element before the current element in the list, not after it. Is it possible to achieve this in some other way?
You can't modify a Collection while iterating over it using an Iterator, except for Iterator.remove().
However, if you use the listIterator() method, which returns a ListIterator, and iterate over that you have more options to modify. From the javadoc for add():
The new element is inserted before the implicit cursor: ... a subsequent call to previous() would return the new element
Given that, this code should work to set the new element as the next in the iteration:
ListIterator<T> i;
i.add(e);
i.previous(); // returns e
i.previous(); // returns element before e, and e will be next
This will work except when the list starts iteration empty, in which case there will be no previous element. If that's a problem, you'll have to maintain a flag of some sort to indicate this edge case.
There might be some trick with ListIterator, but the easiest solution is probably an old style index loop. Verify performance isn't an issue (no linked lists - but ArrayList is fine).
List<Object> myList;
for(int i = 0; i < myList.size(); i++)
{
Object current = myList.get(i);
// Anything you insert after i will be discovered during next iterations
}
How about
List<Foo> fooList = getFooList();
List<Foo> tempFooList = new ArrayList<Foo>()
for(Foo f : fooList)
{
...
// add items that need to be added to temp
tempFooList.add(new Foo());
...
}
fooList.addAll(tempFooList);