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.
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;
}
This question already has an answer here:
ConcurrentModificationException not thrown consistently
(1 answer)
Closed 1 year ago.
G'day everyone. Today I get a quite weird situations regarding ConcurentModificationException.
I have a list like this.
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(2);
list.add(3);
I also have three pieces of code like this.
This will print [2, 3].
for (int i = 0; i < list.size(); i++) {
Integer integer = list.get(i);
if (integer.equals(1)) {
list.remove(integer);
}
}
System.out.println(list);
This will throw exception.
for (Integer integer : list) {
if (integer.equals(1)) {
list.remove(integer);
}
}
System.out.println(list);
This will print [1, 3].
for (Integer integer : list) {
if (integer.equals(2)) {
list.remove(integer);
}
}
System.out.println(list);
I used to think that removing an element inside a for-loop always results ConcurrentModificationException but I might be wrong. Can you guys tell me what create the difference here.
I run the code on Corretto 11.
The point here is that the ConcurrentModificationException is thrown when you access(!) the next element via the iterator, not when checking for the existance of a further element.
In the second snippet you remove the first element then there are still two to go. For the next iteration it will be noticed, that there are more elements which will be accessed and as the expectedModCount changed, the Exception will be thrown.
In the third example however, due to the reduced size, you will have reached the end after the second iteration and no further access will take place and therefore no exception is thrown.
The first example is not meant to throw an exception, because you are not using an iterator, which would check for the concurrent modification in the first place.
As was mentioned earlier first code snippet is not supposed to throw ConcurrentModificationException, because you are not iterating over list.
As regards to other two snippets the equivalent code is following:
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(2);
list.add(3);
Iterator it = list.iterator();
while(it.hasNext()) {
Integer integer = (Integer)it.next();
if (integer.equals(2)) {
list.remove(integer);
}
}
System.out.println(list);
and if you take a look at java.util.ArrayList.Itr implementation:
public boolean hasNext() {
return cursor != size;
}
#SuppressWarnings("unchecked")
public E next() {
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}
you can find out that the reason of such behaviour is caused by cursor = i + 1 in next() call: removing penultimate element in ArrayList decreases size and followed hasNext() call returns false.
A regular for loop and an enhanced one are, slightly, different.
While the regular one loops over the list and gets the individual elements one by one, the enhanced one uses an Iterator. The enhanced for loop works with Iterable objects or an array.
Basically the enhanced for loop translates to this
for(Iterator<Integer> it = list.iterator(); it.hasNext(); ) {
Integer integer = it.next();
if (integer.equals(2)) {
list.remove(integer);
}
}
This also explains why the first enhanced loop throws an exception. As according to the iterator there should be more elements. Calling the next method detects that the underlying collection has changed and thus throws a ConcurrentModificationException.
The last one doesn't because you are already at the end of the iterator and thus no additional call to next.
When you remove an element at index 0, the list shrinks, therefore your list with [1,2,3] is now [2,3]. you then remove index 1 wich remove the 3. You have now [2] in your list. Then you remove index 2 which no longer exist.
You may want to remove only index 0 at every iteration or remove from the last index to the first.
I am trying to use array lists, and I have a row of coordinates. I would like to shift all the coordinates in this row to the front or to the back. I'm not sure if I am on the correct lines here with the code.
List<Coordinate> coordinates = new ArrayList<>();
void addCoordinateToList(Coordinate singleCoordinate) {
coordinates.add(singleCoordinate)
}
void addCoordinateToBackList(ArrayList<> coordinateList) {
for(int i = 0; i < coordinates.size(); i++) {
coordinateList.add(i, coordinateList(i));
}
}
void addCoordinateToFrontList(ArrayList<> coordinateList) {
for(int i = coordinates.size(); i > 0; i--) {
coordinateList.add(i, coordinatesList(i));
}
}
This is not final code, its just writing thoughts out at the moment.
Well, you don't need to use a for loop here.
You could instead utilize the addAll method to achieve what you want:
void addCoordinatesToBack(List<Coordinate> coordinateList) {
coordinates.addAll(coordinateList);
}
void addCoordinatesToFront(List<Coordinate> coordinateList) {
coordinates.addAll(0, coordinateList);
}
addAll has two forms:
addAll(Collection c) adds all elements of the specified Collection at the end of the list;
addAll(int position, Collection c) adds all elements of the specified Collection at the given position. Use position 0 to add them at the beginning of the list.
Also note that I have used List instead of ArrayList with your parameters, as this makes it more flexible.
Note that this is not quite the same as reversing lists.
This functionality is built into the List interface. You can use the following functions for that:
List<String> myList = new ArrayList<>();
//adds to the end of the list
myList.add("reading");
myList.addAll(List.of("the","documentation","first!"));
//adds to the front of the list
myList.add(0,"with");
myList.addAll(0,List.of("It","begins");
Your code
void addCoordinateToBackList(ArrayList<> coordinateList) {
for(int i = 0; i < coordinates.size(); i++) {
coordinateList.add(i, coordinateList.get(i));
}
}
will endlessly add the first element of the original list to beginning of itself. Note that I added the call to List.get(int).
Your last method will throw an ArrayIndexOutOfBounds exception as index i=coordinates.size() is out of bounds. You probably need to change
void addCoordinateToFrontList(ArrayList<> coordinateList) {
for(int i = coordinates.size() - 1; i >= 0; i--) {
coordinateList.add(i, coordinatesList.get(i));
}
}
But this will again add endlessly the last element of the list to itself.
Probably what you want to achieve is:
List<Object> coordinateList = new ArrayList<>();
...
java.util.Collections.reverse(coordinateList);
This will reverse the order of the elements in the list. Note that it will work on the given list and not return anything. This will work only on modifiable lists.
EDIT:
You probably mean to "rotate" the elements, right? There is also the method Collections.rotate(List input, int distance). The documentation:
Rotates the elements in the specified list by the specified distance. After calling this method, the element at index i will be the element previously at index (i - distance) mod list.size(), for all values of i between 0 and list.size()-1, inclusive. (This method has no effect on the size of the list.)
For example, suppose list comprises [t, a, n, k, s]. After invoking Collections.rotate(list, 1) (or Collections.rotate(list, -4)), list will comprise [s, t, a, n, k].
This works in both directions.
I want to loop through a LinkedList using For each and access the element after the one I am at right now. If I would use an Array and the usual for(int i = 0; i < ... ; i++), I would be looking for the element i+1. Is there a possibility of reaching the element after the one I am at right now?
Is there a possibility of reaching the element after the one I am at right now?
If you use a simple "for each" loop, then No. The "current position" within the list is encoded to the list's Iterator. When you use "for each", the Iterator is hidden from your application.
Instead you need to do something like this:
List<Element> list = ...
Element current = null;
Element next = null;
Iterator<Element> it = list.iterator();
while (it.hasNext()) {
current = next;
next = it.next();
if (current == null) {
continue;
}
// process 'current' and use `next` when you need to refer to
// the following on element.
}
if (next != null) {
// process 'next' as the last element.
}
Notes:
If null is a valid list element, then use a flag instead.
Using two iterators for the same list might give you a neater solution.
You could also do something similar to this using a for each ... and keeping track of the "previous" element in a variable, like I do above. See #Jezor's answer.
It is inadvisable to use get(i) on a (large) LinkedList because get(int) is an O(N) operation for a LinkedList in the general case.
You can neither determine the index of next element in enhanced for loop nor it's value.
You can keep the reference to previous element though:
// List is initialized somewhere in the code.
List<Element> elements = ...;
Element previousElement = null;
for (Element element: elements) {
if (previousElement != null) {
// ... your code here...
// previousElement is elements[i]
// element is elements[i + 1]
}
previousElement = element;
}
In the above example you can instantiate previousElement with a null object to avoid the null check.
What you really want to use is good, old for loop with a counter:
List<Element> elements = ...;
for (int i = 0; i < elements.size(); ++i) {
// elements.get(i) is elements[i]
// elements.get(i + 1) is elements[i + 1]
// But be careful, (i + 1) will be out of bounds for the last element!
}
Don't make your life unnecessarily complicated.
If you're using the auto-iterator for-each style loop such as:
for (T elem: myList) {
// ...
}
then there isn't an immediate way to access the "next" element while you're looking at the current one without saving a reference to the element you last saw. It is also possible with using indexOf, but this approach gets very messy when duplicates are found in the list. Regardless, I think your problem would be better addressed using indexing over the list instead.
If you're iterating over your LinkedList object using indexed-based access (as opposed to an iterator or for-each, for example,) you can do:
for (int i = 0; i < myList.size(); i++) {
// ...
if ((i + 1) < myList.size()) {
T nextElem = myList.get(i+1); // fetch the element at the next index
// then do whatever you want with "nextElem"
}
// ...
}
where T refers to the type of LinkedList you are using, i.e. String if your list definition was something like LinkedList<String> myList = new LinkedList<>();.
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 ;)