In a program, I have a HashSet of Foo:
final Set<Foo> set = new HashSet<>();
// add a lot of elements to the set
class Foo {
public void destroy() {
// other stuff [such as removing this as event handler]
set.remove(this);
}
}
I want to call destroy() for all members of the set.
The purpose of the destroy() method is to remove the element as handler for events and from the set.
This is what I have tried:
Use an Iterator / for each loop - throws ConcurrentModificationException:
for (Iterator<Foo> i = set.iterator(); i.hasNext(); ) { i.next().destroy() }
Remove one element at the time - horrible inefficient:
while (!set.isEmpty()) { set.iterator().next().destory(); }
I am looking for a solution to this problem that works well with very many elements in the set. Thank you very much.
You are almost done in your first attempt.
Try
for (Iterator<Foo> i = set.iterator(); i.hasNext(); ) {
Foo foo = i.next();
// other stuff with foo. Something like foo.someOtherStuff();
i.remove();
}
That will remove safely from the set. Need not to call destroy even.
Related
In the past, my app is record app
I use ArrayList ,but ArrayList occur memory leak
`private ArrayList<OutputInputPair>> pairs = new ArrayList<OutPutInputPair>();`
so, when I click record stop button execute pairs.clear(); pairs = null;
but if user never click record stop button. always occur memory leak.
so I use WeakHashMap in reference this site
ArrayList<WeakReference<Runnable>> - How to tidy up best?
in the past, I declare on global variable
private ArraytList<OutputInputPair> pairs = new ArrayList<OutputInputPair>();
I changed
private WeakHaspMap<OutputInputPair, Void> pairs = new WeahHashMap<OutputInputPair, Void>();
and Iterator<OutputInputPair> iterator = pairs.keySet().iterator(); declare on global variable
According to my plan, execute my method.
but if I declare WeakHashMap on global variable not execute my method.
my method source
public void process() {
while(iterator.hasNext()) {
OutputInputPair pair = iterator.next();
//data insert on queue
}
while (!stopped) { //when I click record stop button, stopped is true
while(iterator.hasNext()) {
OutputInputPair pair = iterator.next();
Log.d(TAG, "<<<<<process>>>>"); //not show this log
recordstart(pair);
}
}
}
but if write Iterator<OutputInputPair> iterator = pairs.keySet().iterator();on my method, execute my method.
#Override
public void process() {
Iterator<OutputInputPair> iterator = pairs.keySet().iterator(); //
while(iterator.hasNext()) {
OutputInputPair pair = iterator.next();
//data insert on queue
}
while (!stopped) { //when I click record stop button, stopped is true
while(iterator.hasNext()) {
OutputInputPair pair = iterator.next();
Log.d(TAG, "<<<<<process>>>>"); //not show this log
recordstart(pair);
}
}
}
this source execute my method.
in other words,why add 'Iterator iterator = pairs.keySet().iterator();` on global variable, not execute my method?
Why I want to be a global variable, if I add in my method, It runs indefinitely. because while(!stopped) .
please help me
thanks.
It's hard to say for sure without knowing more context to your code, but if you look at the docs for HashMap.keySet it reads
If the map is modified while an iteration over the set is in progress (except through the iterator's own remove operation), the results of the iteration are undefined.
So if you initialize an iterator over the keySet in a static variable (what you're calling "global" I guess), and then some other part of your code modifies the entries in the hash map, it could have unpredictable results.
I have the following code:
class Action {
public void step(Game game) {
//if some condition met,
// then remove self from action stack
game.actionStack.remove(this);
}
class Game (
public ArrayList<Action> actionStack;
public Game() {
actionStack = new Arraylist<Action>();
actionStack.add(new Action());
while (true) {
for (Action action : this.actionStack) {
action.step(this);
}
}
}
}
An exception gets thrown when game.actionStack.remove(this); occurs. Is there a way to remove the element safely from inside the Action class like I want?
I'm guessing you're getting a ConcurrentModificationException because you're calling the list remove method while iterating it. You can't do that.
An easy fix is to work on a copy of the array when iterating:
for (Action action : new ArrayList<>(this.actionStack)) {
action.step(this);
}
A slightly more efficient fix is to use an explicit Iterator and call its remove method. Perhaps have step() return a boolean indicating whether it wants to remain in the list for the next step or not:
for (Iterator<Action> it = this.actionStack.iterator(); it.hasNext();) {
Action action = it.next();
if (!action.step(this)) {
it.remove();
}
}
From : the java tutorial we get the following:
Iterators
...
Note that Iterator.remove is the only safe way to modify a collection during iteration; the behavior is unspecified if the underlying collection is modified in any other way while the iteration is in progress.
Use Iterator instead of the for-each construct when you need to:
Remove the current element. The for-each construct hides the iterator, so you cannot call remove. Therefore, the for-each construct is not usable for filtering.
Iterate over multiple collections in parallel.
The following method shows you how to use an Iterator to filter an arbitrary Collection — that is, traverse the collection removing specific elements.
static void filter(Collection<?> c) {
for (Iterator<?> it = c.iterator(); it.hasNext(); )
if (!cond(it.next()))
it.remove();
}
This simple piece of code is polymorphic, which means that it works for any Collection regardless of implementation. This example demonstrates how easy it is to write a polymorphic algorithm using the Java Collections Framework.
Note: I assume, you implemented equals and hashCode methods for your class
You need to use iterator to remove like below;
class Game (
public ArrayList<Action> actionStack;
public Game() {
actionStack = new Arraylist<Action>();
actionStack.add(new Action());
while (true) {
for (Iterator<Action> it = this.actionStack.iterator(); it.hasNext(); ) {
it.remove();
}
}
}
}
Edit: step function is doing simple remove job. I move it to Game constructor
I suspect that you are getting a Concurrent Modification Exception. I would suggest you do it like this
class Action {
public void step(Game game) {
//if some condition met,
// then remove self from action stack
List<Action> tmpActionList = new List<Action>();
tmpActionList = game.actionStack
tmpActionList.remove(this);
game.actionStack = tmpActionList;
}
}
Let me know if it works.
public void putExpensiveWineCaseBack(double notBiggerThan)
{
Iterator<WineCase> it = basket.iterator();
WineCase checkedWineCase = null;
while( it.hasNext() )
{
checkedWineCase = it.next();
double checkedPrice = checkedWineCase.getPrice();
int i=0;
for(i=0; i<basket.size(); i++)
{
if(checkedPrice > notBiggerThan)
{
basket.remove(i);
}
}
}
}
}
This code is compiling. The problem is that when executed I get this error:
java.util.ConcurentModificationexception:
null(in java.util.ArrayList$Itr)
for this line:
checkedWineCase = it.next();
What am I missing ?
Change from
basket.remove(i);
to
it.remove();
You're calling basket.remove() but should call it.remove() instead.
You are removing items from the list in the loop where you are iterating through the items in the list. That is the cause of the ConcurrentModificationException.
'null pointer' does not exactly describe your problem, rather it is the name of the exception you received: ConcurentModificationexception
When an iterator is instantiated, it provides access to a certain group of objects, in this case, the contents of 'basket'. It might take some time to go from getting the first object in the iterator to getting the last one.
Now, what happens if the objects in the 'basket' change? The iterator is designed to be 'fail-fast', meaning if the basket has changed, you will immediately get an exception the next time you try to use the Iterator.
This is happening because in some cases you call 'basket.remove()' before you have finished iterating over everything in the basket. You may wish to 'remember' which things should be removed from the basket, and then remove them only when you are completely done with the iterator.
Google 'java iterator concurrentmodificationexception' to see many more explanations of the issue you are encountering.
The problem is you are removing elements from basket while you are iterating over it.
Actually I'm not sure what you are trying to do, as that for loop makes not much sense to me. But I guess you want to remove the element from the Set if the price is larger than notBiggerThan.
So maybe you should try like this:
while(it.hasNext()) {
checkedWineCase = it.next();
double checkedPrice = checkedWineCase.getPrice();
if(checkedPrice > notBiggerThan)
{
it.remove();
}
}
You should not modify the collection while iterating, except by way of Iterator.remove().
The problem comes from your call to basket.remove(i);
I do not completely understand what you are trying to do with that inner for loop (currently it looks like it will remove everything from your basket if any have a price > than the maximum), maybe you want the following:
public void putExpensiveWineCaseBack(double notBiggerThan)
{
Iterator<WineCase> it = basket.iterator();
WineCase checkedWineCase = null;
while( it.hasNext() )
{
checkedWineCase = it.next();
double checkedPrice = checkedWineCase.getPrice();
if(checkedPrice > notBiggerThan)
{
it.remove();
}
}
}
if have the following problem:
I have a List which i am going through using the enhanced for loop. Every time i want to remove sth, out of the list, i get a ConcurrentModificationException. I already found out why this exception is thrown, but i don`t know how i can modify my code, so that its working. This is my code:
for(Subject s : SerData.schedule)
{
//Checking of the class is already existing
for(Classes c : s.classes)
{
if(c.day == day &c.which_class == which_class)
{
int index = getclassesindex(s.classes, new Classes(day, which_class));
synchronized (s) {
s.classes.remove(index);
}
}
}
//More code....
}
I also tried out this implementation.
for(Subject s : SerData.schedule)
{
//Checking of the class is already existing
Iterator<Classes> x = s.classes.iterator();
while(x.hasNext())
{
Classes c = x.next();
if(c.day == day &c.which_class == which_class)
{
int index = getclassesindex(s.classes, new Classes(day, which_class));
synchronized (s) {
s.classes.remove(index);
}
}
}
//More code....
}
not working either...
Is there a common used, standard solution? (Hopefully sth. that is not obvious :D )
The main reason this issue occurs is because of the semantic meaning of your for-each loop.
When you use for-each loops, the data structure that is being traversed cannot be modified.
Essentially anything of this form will throw this exception:
for( Object o : objCollection )
{
// ...
if ( satisfiesSomeProperty ( o ) )
objList.remove(o); // This is an error!!
// ...
}
As a side note, you can't add or replace elements in the collection either.
There are a few ways to perform this operation.
One way is to use an iterator and call the remove() method when the object is to be removed.
Iterator <Object> objItr = objCollection.iterator();
while(objItr.hasNext())
{
Object o = objItr.next();
// ...
if ( satifiesSomeProperty ( o ) )
objItr.remove(); // This is okay
// ...
}
This option has the property that removal of the object is done in time proportional to the iterator's remove method.
The next option is to store the objects you want to remove, and then remove them after traversing the list. This may be useful in situations where removal during iteration may produce inconsistent results.
Collection <Object> objsToRemove = // ...
for( Object o : objCollection )
{
// ...
if ( satisfiesSomeProperty ( o ) )
objsToRemove.add (o);
// ...
}
objCollection.removeAll ( objsToRemove );
These two methods work for general Collection types, but for lists, you could use a standard for loop and walk the list from the end of the list to the front, removing what you please.
for (int i = objList.size() - 1; i >= 0; i--)
{
Object o = objList.get(i);
// ...
if ( satisfiesSomeProperty(o) )
objList.remove(i);
// ...
}
Walking in the normal direction and removing could also be done, but you would have to take care of how incrementation occurs; specifically, you don't want to increment i when you remove, since the next element is shifted down to the same index.
for (int i = 0; i < objList.size(); i++)
{
Object o = objList.get(i);
// ...
if ( satisfiesSomeProperty(o) )
{
objList.remove(i);
i--;
}
//caveat: only works if you don't use `i` later here
// ...
}
Hope this provides a good overview of the concepts and helps!
Using Iterator.remove() should prevent the exception from being thrown.
Hm if I get it right you are iterating over a collection of classes and if a given class matches some criteria you are looking for the its index and try to remove it?
Why not just do:
Iterator<Classes> x = s.classes.iterator();
while(x.hasNext()){
Classes c = x.next();
if(c.day == day && c.which_class == which_class) {
x.remove();
}
}
Add synchronization if need be (but I would prefer a concurrent collection if I were you), preferably change the "==" to equals(), add getters/setters etc. Also the convention in java is to name variables and methods using camelCase (and not separating them with "_").
Actually this is one of the cases when you have to use an iterator.
From the javadoc on ConcurrentModificationException:
"if a thread modifies a collection directly while it is iterating over the collection with a fail-fast iterator, the iterator will throw this exception."
So within your
for (Classes c : s.classes)
you are executing
s.classes.remove(index)
and the iterator is doing just what its contract says. Declare the index(es) in a scope outside the loop and remove your target after the loop is done.
Iterator<Classes> classesIterator = s.classes.iterator();
while (classesIterator.hasNext()) {
Classes c = classesIterator.next();
if (c.day == day && c.which_class == which_class) {
classesIterator.remove();
}
}
There is no general solution for Collection subclasses in general - most iterators will become invalid if the collection is modified, unless the modification happens through the iterator itself via Iterator.remove().
There is a potential solution when it comes to List implementations: the List interface has index-based add/get/set/remove operations. Rather than use an Iterator instance, you can iterate through the list explicitly with a counter-based loop, much like with arrays. You should take care, however, to update the loop counter appropriately when inserting or deleting elements.
Your for-each iterator is fail-fast and this is why remove operation fails as it would change the collection while traversing it.
What implementation of List interface are you using?
Noticed synchronisation on Subject, are you using this code concurrently?
If concurrency is the case, then I would recommend using CopyOnWriteArrayList. It doesn't need synchronisation and its for-each iterator doesn't throw ConcurrentModificationException.
I'm a little puzzled over something. Java's documentation tells us that there is no defined behavior when removing items from a collection while iterating over that collection using an Iterator object and that the only safe way to do so is to use Iterator.remove().
How then, would you safely remove an event handler from an ArrayList if, in the course of iterating through the list one of the handlers has decided that it's time to remove itself as a listener?
// in public class Dispatcher
public void dispatchEvent(){
Iterator<IEventHandler> iterator = mHandlers.iterator();
IEventHandler handler = null;
while(iterator.hasNext()){
handler = iterator.next();
handler.onCallbackEvent();
}
}
public void insertHandler(IEventHandler h){
mHandlers.add(h);
}
public void removeHandler(IEventHandler h){
mHandlers.remove(h);
}
Meanwhile, the handler was instantiated like this...
final Dispatcher d = new Dispatcher();
d.insertHandler(new IEventHandler(){
#Override
public void onCallbackEvent(){
Log.i(" callback happened ");
d.removeHandler(this);
}
});
See the potential problem? You're removing the handler from the ArrayList as a result of the onCallbackEvent() declared in that specific handler while you're still iterating using the Iterator.
Is this an intractable problem? What's the safe way to handle this situation?
This is a very common problem when implementing an event system. The only solution is to copy the list of handlers on change. You can do this yourself in the insertHandler/removeHandler methods or just use CopyOnWriteArrayList.
You could reimplement removeHandler to store the handlers scheduled for removal.
public void removeHandler(IEventHandler h){
mHandlersToRemove.add(h);
}
and then remove them before you do any dispatching.
public void dispatchEvent(){
mHandlers.removeAll(mHandlersToRemove);
mHandlersToRemove.clear();
...
You could also remove at the end of dispatchEvent, but then you could only remove from within handlers. (Otherwise you might dispatch to handlers that were removed.)
If you're interested in a theoretical solution to this problem, you can look at how C++ implements iterators. In an stl vector, the iterator has an erase method that returns the next valid iterator.
It would look something like this:
for (itr = listA.begin(); itr != listA.end(); )
{
if ( shouldRemove(*itr) ) {
itr = listA.erase(itr);
}
else {
++itr;
}
}
Of course, this example doesn't apply to your question since it's both in C++ and it would be awkward to propagate the new iterator up to the top-level loop (or add a return value to your call for a "remove" condition). But maybe there's a similar java implementation somewhere out there : )