I'm trying to iterate throuh a list while already looping through it (nested loops). Consider the code below:
ArrayList<Integer> list = new ArrayList<Integer>(); // add some values to it
for(int i : list) { // ConcurrentModificationException
Iterator iterator = list.iterator();
while(iterator.hasNext()) {
int n = iterator.next();
if(n % i == 0) {
iterator.remove();
}
}
}
The example above results in a ConcurrentModificationException. The condition to remove an element is, of course, just an example.
I'm sure I'm just missing something; but how should I construct a loop that achieves the same thing in Java without throwing an exception?
Obviously modifying list when you iterate over it causing the execption.
You can use another list to maintain the list of elements to be removed and remove them at the end.
ArrayList<Integer> list = new ArrayList<Integer>(); // add some values to it
ArrayList<Integer> del = new ArrayList<Integer>(); // Elements to be deleted
for(int i : list) { // ConcurrentModificationException
Iterator iterator = list.iterator();
while(iterator.hasNext()) {
int n = iterator.next();
if(n % i == 0) {
del.add(n);
}
}
}
list.removeALL(del);
Make the outer iteration iterate over a copy of the list.
for (int i : new ArrayList<>(list)) {
Iterator<Integer> iterator = list.iterator();
while (iterator.hasNext()) {
int n = iterator.next();
if (n % i == 0) {
iterator.remove();
}
}
}
You are getting ConcurrentModificationException because, while doing for loop you are trying to modify the list.
I am not sure whether following is elegant solution or not, but something like below may work:
Iterator<Integer> iterator = list.iterator();
int i=1;
while (iterator.hasNext()) {
int n = iterator.next();
if (n % i == 0) {
iterator.remove();
}
i++;
}
You cannot remove an item from a list that is being iterated. One option is to add the items that you need to another list. Finally you have list with the items you need. Or you can iterate over the clone of your original list.
i do some thing pretty similar to you. hav e alook at this code .
out:for(int h=0; h<tempAl.size(); h++) {
if(tempAl.get(0).split("\\s")[0].equals("OFF")){
tempAl.remove(0);
h=-1;
continue;
}
if(tempAl.get(h).split("\\s")[0].equals("ON")){
ONTime= tempAl.get(h);
///rest fof the code
}
i think you could also change the index after removing element from the arraylist.
I haven't tried, but either use:
List<Integer> list = new ArrayList<Integer>();
// add some values to it
for(Iterator<Integer> iterator1 = list.iterator(); iterator1.hasNext();) {
int i = iterator1.next();
for(Iterator<Integer> iterator2 = list.iterator(); iterator2.hasNext();){
int n = iterator.next();
if(n % i == 0) {
iterator2.remove();
}
}
}
or if this still throws the ConcurrentModificationException (I'm not sure what happens if you use 2 iterators backed by the same list), then use:
List<Integer> list = new ArrayList<Integer>();
// add some values to it
for(int i : new ArrayList(list)){ // copy list
...
}
foreach java syntax hides an iterator but as hiding it, it is not possible to call remove method on this one.
So I would do:
ArrayList<Integer> list = new ArrayList<Integer>(); // add some values to it
int count = 0;
for(Iterator<Integer> it = list.iterator();it.hasNext();count++){ //increments count++
Integer currentInt = it.next();
if(currentInt % count == 0){
it.remove();
}
}
You can see that the same feature is achieved without the need of a secondary iterator.
You can't iterate through the same list in the same time.
To sum up, a modcount variable is used to detect unexpected change of itself everytime a list is parallely changed or iterated over.
Leading thus to a ConcurrentModificationException.
It appears very often with multithreaded environment and developers must be aware of it.
Furthermore, prefer use for loop instead while loop to iterate over a collection.
Why ?
Because with the while way, you let the iterator object still in scope after the loop whereas with for, it doesn't. A simple ackward call to it.next() would end up with a NoSuchElementException.
It is a best practice to keep ;)
Related
Given a list of Elements. For example list1 = {a,b,c,d,e}
I want to return an iterator that only iterates over the elements that satisfy a certain condition.
If for example b,d,e meet that condition, then the return value is an iterator that iterates only over those elements b,d,e.
Not allowed to use builtin java collections.
Also I have built my own linked list and iterator.
I have tried doing this by creating a list and adding only the elements where the condition is met.
Then returning an iterator over that new list.
The problem is, that later on i want to remove elements with this iterator and those removed elements should also be removed in the original list.
Is this somehow possible?
I am aware that this does not work:
public Iterator<Y> iterator(X x) {
MyLinkedList<Y> temp = new MyLinkedList<>();
for (int i = 0; i < listY.size(); i++) {
if(!x.satisfies(listY.get(i))){
temp.addFirst(listY.get(i));
listY.remove(i);
}
}
MyIterator<Y> iter1 = new MyIterator<>(listY);
for (int i = 0; i < temp.size(); i++) {
listY.addFirst(temp.get(i));
}
return iter1;
}
when running the code below i get the above exception but i don't know why or how to fix it.
Im pretty sure it comes from
for(int node : adjacent(currentnode))
{
//System.out.println(adjacent(currentnode));
//System.out.println(node);
if (remainingnodes.contains(getNode(node)))
{
adjacent.add(node);
remainingnodes.remove(getNode(node));
//System.out.println(remainingnodes);
}
}
getNode just takes an integer and returns the corresponding node. I used to not get the exception before i used getNode in remainingnodes.contains but at the time it was removing the components so i had to change it and now i get the exception.
public int distance(int target, List<Integer> detectives)
{
List<Integer> adjacent = new ArrayList<>();
Set<Node<Integer>> remainingnodes = new HashSet<Node<Integer>>();
List<Integer> currentnodes = new ArrayList<>();
int distance = 0;
int i = 0;
currentnodes.add(target);
remainingnodes = graph.getNodes();
remainingnodes.remove(getNode(target));
while (detectives.size() != 0)
{
for (int currentnode : currentnodes)
{
for(int node : adjacent(currentnode))
{
//System.out.println(adjacent(currentnode));
//System.out.println(node);
if (remainingnodes.contains(getNode(node)))
{
adjacent.add(node);
remainingnodes.remove(getNode(node));
//System.out.println(remainingnodes);
}
}
for (int detective : detectives)
{
if (currentnode == detective)
{
distance = distance + i;
detectives.remove(detective);
}
}
}
currentnodes.clear();
currentnodes = adjacent;
i++;
}
Thanks
Arthur
You cant modify the List in for each loop. If you want to remove any elements in loop use iterator. You can remove elements using iterator.remove(); which deletes current element in the iterator.
As you are itterating over a list and trying to remove element from the same list, a ConcurrentModificationException shall occur.
You first iterate over the list then you determine the position of the element you want to remove from list and store it in a temporary variable, then after the iteration is complete, just remove the particular element based on stored position.
Your assumption is correct. While iterating over a List, you cannot alter it, like you are doing when calling adjacent.add(node) inside the for loop.
This is called concurrent modification, thus the exception ConcurrentModificationException.
Being new to Java, the following code confuses me. I'm trying to do a simple loop based on a list.
List memberships = getMembership(username);
for( Iterator<Integer> single = memberships.iterator(); single.hasNext(); )
{
System.out.println(print_the_current_string_in_list);
}
I have the following questions:
The loop never stops with the above, even though I only have three items in the list. Why is this?
How can I output the current string in the list?
Hopefully your List if of type String and not Integer so it should be
List<String> memberships = getMembership(username);
There are multiple ways to loop over the data for example:
for(String single : memberships) {
System.out.println(single);
}
Another way:
for(int i = 0; i < memberships.size(); i++) {
System.out.println(memberships.get(i));
}
Using the Iterator
for(Iterator<String> iterator = membership.iterator(); iterator.hasNext();) {
System.out.println(iterator.next());
}
Instead of using a for loop you may use an Iterator with a while loop
Iterator<String> iterator = membership.iterator();
while(iterator.hasNext()) {
System.out.println(iterator.next());
}
Try an advanced for loop, like so:
for(String membership : memberships)
System.out.println(membership);
You can use the foreach statement, which uses the iterator that the list has already implemented.
And you should also specify the type of the elements that the list will contain in the List declaration, like this:
List<String> memberships = getMembership(username);
for( String m : memberships )
{
System.out.println(m);
}
You need to actually iterate over the members with next() method from Iterator:
for (Iterator<Integer> single = memberships.iterator (); single.hasNext (); ) {
Integer next = single.next ();
System.out.println (next);
}
Also, you can use the new for each construct:
for (Integer current : memberships)
System.out.println (current);
You haven't iterated through the list.Use next() method.Thats why its going into an infinite loop.
for( Iterator<Integer> single = memberships.iterator(); single.hasNext();{
System.out.println( single.next());
}
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.
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.