java.util.ConcurrentModificationException using 2 iterators - java

I am trying to iterate through a HashMap using 2 iterators. Firstly for every key(Integer) in the hash I compute "similar" numbers(it really doesn't matter what similar numbers are in this particular case) and then I have to delete the keys which are similar to the current key by making them values of the current key. I keep receiving this exception
Exception in thread "main" java.util.ConcurrentModificationException. What could be the cause? Do I have to use a ConcurrentHashMap?
This is the code I am compiling:
Set<Node> keySet = hash.keySet();
Iterator<Node> it = keySet.iterator();
while(it.hasNext()){
Node key = it.next();
ArrayList<Integer> similar = getAppropriateNum(key.getLabel(), 2);
for(int j = 0; j < similar.size(); j++){
Iterator<Node> it2 = keySet.iterator();
while(it2.hasNext()){
Node nod = it2.next();
if(nod.getLabel() == similar.get(j) && !nod.equals(key)){
it2.remove();
hash.put(key, nod);
}//end if
}//end while
}//end for
}//end while

The problem is that you are removing an item using an iterator (good practice) but the other iterator is not aware of that. Hence, the call to it.next() fails.
You should try to use only one iterator or remove items after looping.
EDIT : After analyzing your question, it seems that your need is to create a Collection of unique items. This makes me think that you would like to use a Set with a well-formed Comparator. In this way, adding all your items to your Set will automatically remove duplicates.

Related

Java how to remove element from List efficiently

Ok, this is a proof-of-concept I have on my head that has been bugging me for a few days:
Let's say I have:
List<String> a = new ArrayList<String>();
a.add("foo");
a.add("buzz");
a.add("bazz");
a.add("bar");
for (int i = 0; i < a.size(); i++)
{
String str = a.get(i);
if (!str.equals("foo") || !str.equals("bar")) a.remove(str);
}
this would end up with the list ["foo", "bazz", "bar"] because it would read the string at index 1 ("buzz"), delete it, the string at index 2 ("bazz") would jump to index 1 and it would be bypassed without being verified.
What I came up with was:
List<String> a = new ArrayList<String>();
a.add("foo");
a.add("buzz");
a.add("bazz");
a.add("bar");
for (int i = 0; i < a.size(); i++)
{
String str = a.get(i);
boolean removed = false;
if (!str.equals("foo") || !str.equals("bar"))
{
a.remove(str);
removed = true;
}
if (removed) i--;
}
It should work this way (atleast it does in my head lol), but messing with for iterators is not really good practice.
Other way I thought would be creating a "removal list" and add items to that list that needed to be removed from list a, but that would be just plain resource waste.
So, what is the best practice to remove items from a list efficiently?
Use an Iterator instead and use Iterator#remove method:
for (Iterator<String> it = a.iterator(); it.hasNext(); ) {
String str = it.next();
if (!str.equals("foo") || !str.equals("bar")) {
it.remove();
}
}
From your question:
messing with for iterators is not really good practice
In fact, if you code oriented to interfaces and use List instead of ArrayList directly, using get method could become into navigating through all the collection to get the desired element (for example, if you have a List backed by a single linked list). So, the best practice here would be using iterators instead of using get.
what is the best practice to remove items from a list efficiently?
Not only for Lists, but for any Collection that supports Iterable, and assuming you don't have an index or some sort of key (like in a Map) to directly access to an element, the best way to remove an element would be using Iterator#remove.
You have three main choices:
Use an Iterator, since it has that handy remove method on it. :-)
Iterator<String> it = list.iterator();
while (it.hasNext()) {
if (/*...you want to remove `it.next()`...*/) {
it.remove();
}
}
Loop backward through the list, so that if you remove something, it doesn't matter for the next iteration. This also has the advantage of only calling list.size() once.
for (int index = list.size() - 1; index >= 0; --index) {
// ...check and optionally remove here...
}
Use a while loop instead, and only increment the index variable if you don't remove the item.
int index = 0;
while (index < list.size()) {
if (/*...you want to remove the item...*/) {
list.removeAt(index);
} else {
// Not removing, move to the next
++index;
}
}
Remember that unless you know you're dealing with an ArrayList, the cost of List#get(int) may be high (it may be a traversal). But if you know you're dealing with ArrayList (or similar), then...
Your first example will likely cause off-by-one errors, since once you remove an object your list's indexes will change. If you want to be quick about it, use an iterator or List's own .remove() function:
Iterator<String> itr = yourList.iterator();
while (itr.hasNext()) {
if ("foo".equals(itr.next()) {
itr.remove();
}
}
Or:
yourList.remove("foo");
yourList.removeAll("foo"); // removes all
ArrayList.retainAll has a "smart" implementation that does the right thing to be linear time. You can just use list.retainAll(Arrays.asList("foo", "bar")) and you'll get the fast implementation in that one line.

Getting the clicked object from an array list

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.

How to remove element From Linked Hash Set in java?

I want to know Different ways to remove element from Linked Hash Set. I tried following code
LinkedHashSet<String> lhs = new LinkedHashSet<String>();
for(int i=0;i<10;i++)
lhs.add(String.valueOf(i));
Iterator<String> it=lhs.iterator();
System.out.println("removed?=="+lhs.remove("1"));
while(it.hasNext())
{
System.out.println("lhs"+it.next());
}
i got following output
removed?==true
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.LinkedHashMap$LinkedHashIterator.nextEntry(Unknown Source)
at java.util.LinkedHashMap$KeyIterator.next(Unknown Source)
at preac.chapter1.Start.main(Start.java:321)
What i miss? thanks in advance.
P.S I have also tried iterator.remove() method but got Illegal State Exception
EDIT
I just came to know i have to use iterator remove method. then what it is use of Link Hash Set remove method ? In which cases we should use this method?
Try to remove element using Iterator.remove like below,
LinkedHashSet<String> lhs = new LinkedHashSet<String>();
for (int i = 0; i < 10; i++) {
lhs.add(String.valueOf(i));
}
Iterator<String> it=lhs.iterator();
// System.out.println("removed?=="+lhs.remove("1"));
while(it.hasNext()) {
String value=it.next();
if("1".equals(value)){
it.remove();
}
else{
System.out.println("lhs "+value);// Print the other value except 1
}
}
System.out.println(lhs);// After remove see the result here.
You get the exception because the iterator realizes that you called remove after creating the iterator (using an internal modification counter).
Let's assume add and remove increment the modification counter by 1.
When the iterator is created, it sees a modification counter of 10.
However, when the iterator is first accessed, the modification counter is 11, due to the call to remove, hence the exception.
Switch the statements and it should be fine:
...
System.out.println("removed?=="+lhs.remove("1"));
Iterator<String> it=lhs.iterator();
...

Iterate through a list deleting elements

I want to iterate through some kind of list, checking if its elements meet a property, and if they don't deleting them from the array. What I've thought is something like this:
int index = 0;
for(int i = 0; i < list.size(); ++i) {
if(list.isProperty()) list.delete(index) //We delete the element at list[index]
else ++index;
}
Maybe those aren't the real methods of the list interface in java, but they're quite self-explanatory.
Is this a good approach? Which data structure would fit best if I have to run this operation many times? I don't think an arrayList would work as I'd have to be moving around elements each time I delete and I can't ensure the elements I'll remove are in the head or the tail of the list either.
You can achieve it using iterator.Without having concurrent modification exception.
Say your list consists of object A
List<A> list = new ArrayList<A>();
Iterator<A> iterator = list.iterator();
while (iterator.hasNext()) {
A current = iterator.next();
if(current.isProperty()) {
iterator.remove();;
}
}
You should remove an element from a List using an Iterator. You can use this with ArrayList.
List<YourDataType> yourList = new ArrayList<YourDataType>();
Iterator<YourDataType> it = yourList.iterator();
while (it.hasNext())
it.remove();
With this you can use if-else to specify the element, which should be removed.
This should give you some hints, why you should use an Iterator.

Removing multiple items from ArrayList, shifting indexes

I have an ArrayList that I loop and through some logic I would remove an element at a particular index.
However while I am looping the Arraylist and removing on the way, the ArrayList size and index of particular items are changing as well, resulting in unexpected results.
Anyway to circumvent this?
Here's the code for the iterator approach - substitute your own condition and add generics types <> as needed:
Iterator it = list.iterator();
while(it.hasNext()){
Object o = it.next();
if(someCondition(o)){
it.remove();
}
}
And, as JohnB said in the comments, ArrayList isn't very efficient if you are removing lots of items from large lists...
You can use an Iterator.remove() or iterate backwards.
List<String> list = ...
for(int i= list.size()-1; i>=0; i--)
if(test(list.get(i)))
list.remove(i); // values before `i` are untouched.
or you can decrement the counter.
List<String> list = ...
for(int i= 0; i < list.size(); i++)
if(test(list.get(i)))
list.remove(i--); // move i back as there is one less element.
You could use an iterator which has a remove() method to do exactly that.
Use Iterator for looping. It can be used to remove the elements from the collection.

Categories

Resources