Java delete arraylist iterator - java

I've an ArrayList in Java of my class 'Bomb'.
This class has a method 'isExploded', this method will return true if the bomb has been exploded, else false.
Now I'm trying to iterate through this arraylist, call this method isExploded and remove the element from the list if it returns true.
I know how to iterate:
for (Iterator i = bombGrid.listIterator(); i.hasNext();) {
if () {
i.remove();
}
But I've no idea how to access the method isExploded of the Bomb class itself via the iterator. Does anyone know the answer to this?
Sincerely,
Luxo

You'll need to get the Bomb using next :
for (Iterator i = bombGrid.listIterator(); i.hasNext();) {
Bomb bomb = (Bomb) i.next();
if (bomb.isExploded()) i.remove();
}
Or if you can get an Iterator<Bomb> from your bombGrid (is it an ArrayList<Bomb> ?):
Iterator<Bomb> i = bombGrid.listIterator();
while (i.hasNext()) {
Bomb bomb = i.next();
if (bomb.isExploded()) i.remove();
}
This supposes your iterator supports remove, which is the case for example by the one given by an ArrayList.

If you use Java 5, use generics:
List<Bomb> bombGrid = ...;
for (Iterator<Bomb> i = bombGrid.iterator(); i.hasNext();) {
if (i.next().isExploded()) {
i.remove();
}
}

No, you cannot remove inside an Iterator for ArrayList while iterating on it. Here's Javadoc extract :
The iterators returned by this class's iterator and listIterator methods are fail-fast: if the list is structurally modified at any time after the iterator is created, in any way except through the iterator's own remove or add methods, the iterator will throw a ConcurrentModificationException. Thus, in the face of concurrent modification, the iterator fails quickly and cleanly, rather than risking arbitrary, non-deterministic behavior at an undetermined time in the future.
http://docs.oracle.com/javase/6/docs/api/java/util/ArrayList.html

Related

Iterator inside Iterator ConcurrentModificationException

I am having the following problem:
Given an ArrayList (let's call it list), how can I "double-iterate" through it without getting ConcurrentModificationException?
Here's what I've tried:
iterator out = list.iterator();
iterator in;
while(out.hasNext()){
...
in = list.iterator();
while(in.hasNext()){
...
if(something)
in.remove();
}
You can't do that. A potential solution might be to mark objects to be removed, for example:
final List<Foo> toRemove = new ArrayList<>();
for (Foo a : list)
{
for (Foo b : list)
{
if (something)
{
toRemove.add(b);
}
}
}
list.removeAll(toRemove);
You may need some additional checks to see that the object isn't already marked for removal. It's impossible to say given how vague your example is.
You are trying to modify an iterator. It will give you concurrentModification exception.
In java 8 you can easily remove it using
list.removeIf(someCondition)
Try this link java8 collections
The Iterator instance provided through a call to List#iterator method preserves a count scalar allowing to detect external changes to the Collection container.
When an element is removed from the collection by any other mean than going through the same Iterator#remove(T) call, the count is not updated behind the scenes.
Therefore when you request for the #next() element through the iterator instance, the count is checked against an expected value and if both values does not match (since an element has been removed through another iterator) a ConcurrentModificationException is thrown (even though you may be working in a single threaded environment).
The solution whould be, as #Michael stated, to keep track of the container elements that should be removed then perform a bulk delete:
Collection<Object> temp = new ArrayList<>();
iterator out = list.iterator();
iterator in;
while (out.hasNext()) {
// ...
in = list.iterator();
while (in.hasNext()) {
// ...
if(something)
// just mark the element for deletion
temp.add(in.next());
}
}
// delete all the obsolete elements
list.removeAll(temp);
In collection once iterator creator If you try to modify the content not through same iterator it will throw concurrent exception.If you required some special kind of iterator then you can go ahead and implement your own.

Collection throws or doesn't throw ConcurrentModificationException based on the contents of the Collection [duplicate]

This question already has answers here:
Why is a ConcurrentModificationException thrown and how to debug it
(8 answers)
java.util.ConcurrentModificationException not thrown when expected
(2 answers)
Closed 3 years ago.
The following Java code throws a ConcurrentModificationException, as expected:
public class Evil
{
public static void main(String[] args) {
Collection<String> c = new ArrayList<String>();
c.add("lalala");
c.add("sososo");
c.add("ahaaha");
removeLalala(c);
System.err.println(c);
}
private static void removeLalala(Collection<String> c)
{
for (Iterator<String> i = c.iterator(); i.hasNext();) {
String s = i.next();
if(s.equals("lalala")) {
c.remove(s);
}
}
}
}
But the following example, which differs only in the contents of the Collection, executes without any exception:
public class Evil {
public static void main(String[] args)
{
Collection<String> c = new ArrayList<String>();
c.add("lalala");
c.add("lalala");
removeLalala(c);
System.err.println(c);
}
private static void removeLalala(Collection<String> c) {
for (Iterator<String> i = c.iterator(); i.hasNext();) {
String s = i.next();
if(s.equals("lalala")) {
c.remove(s);
}
}
}
}
This prints the output "[lalala]". Why doesn't the second example throw a ConcurrentModificationException when the first example does?
Short answer
Because the fail-fast behavior of an iterator isn't guaranteed.
Long answer
You're getting this exception because you cannot manipulate a collection while iterating over it, except through the iterator.
Bad:
// we're using iterator
for (Iterator<String> i = c.iterator(); i.hasNext();) {
// here, the collection will check it hasn't been modified (in effort to fail fast)
String s = i.next();
if(s.equals("lalala")) {
// s is removed from the collection and the collection will take note it was modified
c.remove(s);
}
}
Good:
// we're using iterator
for (Iterator<String> i = c.iterator(); i.hasNext();) {
// here, the collection will check it hasn't been modified (in effort to fail fast)
String s = i.next();
if(s.equals("lalala")) {
// s is removed from the collection through iterator, so the iterator knows the collection changed and can resume the iteration
i.remove();
}
}
Now to the "why": In the code above, notice how the modification check is performed - the removal marks the collection as modified, and next iteration checks for any modifications and fails if it detects the collection changed. Another important thing is that ArrayList (not sure about other collections) does not check for modification in hasNext().
Therefore, two strange things may happen:
If you remove the last element while iterating, nothing will be thrown
That's because there's no "next" element, so the iteration ends before reaching the modification-checking code
If you remove the second-to-last element, ArrayList.hasNext() will actually also return false, because the iterator's current index is now pointing at the last element (former second-to-last).
So even in this case, there's no "next" element after the removal
Note that this all is in line with ArrayList's documentation:
Note that the fail-fast behavior of an iterator cannot be guaranteed as it is, generally speaking, impossible to make any hard guarantees in the presence of unsynchronized concurrent modification. Fail-fast iterators throw ConcurrentModificationException on a best-effort basis. Therefore, it would be wrong to write a program that depended on this exception for its correctness: the fail-fast behavior of iterators should be used only to detect bugs.
Edited to add:
This question provides some information on why the concurrent modification check is not performed in hasNext() and is only performed in next().
If you look at the source code for the ArrayList iterator (private nested class Itr), you'll see the flaw in the code.
The code is supposed to be fail-fast, which is done internally in the iterator by calling checkForComodification(), however the hasNext() doesn't make that call, likely for performance reasons.
The hasNext() instead is just:
public boolean hasNext() {
return cursor != size;
}
This means that when you're on the second last element of the list, and then remove an element (any element), the size is reduced and hasNext() thinks you're on the last element (which you weren't), and returns false, skipping the iteration of the last element without error.
OOPS!!!!
From other answers you know what is the right way of removing an element in collection while you are iterating the collection.
I give here the explanation to the basic question.And the answer to your question lies in the below stack trace
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(Unknown Source)
at java.util.ArrayList$Itr.next(Unknown Source)
at com.ii4sm.controller.Evil.removeLalala(Evil.java:23)
at com.ii4sm.controller.Evil.main(Evil.java:17)
In the stacktrace it is obvious that i.next(); line throws the error. But when you have only two elements in the collection.
Collection<String> c = new ArrayList<String>();
c.add("lalala");
c.add("lalala");
removeLalala(c);
System.err.println(c);
When the first one is removed i.hasNext() returns false and i.next() is never executed to throw the exception
you should remove from the iterator (i) not the collection (c) directly;
try this:
for (Iterator<String> i = c.iterator(); i.hasNext();) {
String s = i.next();
if(s.equals("lalala")) {
i.remove(); //note here, changing c to i with no parameter.
}
}
EDIT:
The reason why the first try throws exception while the second one doesn't is simply because of the number of element in your collection.
as the first one will go through the loop more than once and the second one will only iterate once. therefore, it doesn't have the chance to throw exception
You can't remove from list if you're browsing it with "for each" loop.
You can't remove an item from a collection you're iterating over. You can get around this by explicitly using an Iterator and removing the item there. You can use Iterator.
If you use below code you will not get any exception :
private static void removeLalala(Collection<String> c)
{
/*for (Iterator<String> i = c.iterator(); i.hasNext();) {
String s = i.next();
if(s.equals("lalala")) {
c.remove(s);
}
}*/
Iterator<String> it = c.iterator();
while (it.hasNext()) {
String st = it.next();
if (st.equals("lalala")) {
it.remove();
}
}
}

ConcurrentModificationException in ArrayList<Object>

I understand that this exception is occurring because I'm trying to modify a list while I'm iterating through a list, but I don't understand how to get around it.
for(Villager e : tasked)
{
if(!e.hasTask())
{
tasked.remove(e);
}
}
The code is pretty self-explanatory. If the villager "e" does not have a task, it should be removed from this list.
Use a ListIterator, which allows you to make changes to the list through which you are iterating.
The code you use is almost indentical in use to an iterator, but removing elements has to be done explicitly using the remove() method of the iterator.
e.g.
Iterator itr = tasked.iterator();
while(itr.hasNext()) {
Villager e = itr.next();
if(!e.hasTask()) {
itr.remove();
}
}
The ConcurrentModificationException is a RuntimeException that may be thrown by methods that have detected concurrent modification of an object, when such modification is not permissible. An example of not permissible behavior is when a thread tries to modify the internal structure of a Collection, while another thread is iterating over it.
Use Iterator's remove method.
Iterator<Village> villageItr = tasked.iterator();
while(villageItr.hasNext()){
Village e=villageItr.next();
if(!e.hasTask()){
//remove that element from collection
villageItr.remove();
}
}
Create separate list (e.g. itemsToRemove), that contains all items you want to remove and then use
tasked.removeAll(itemsToRemoveList)
e.g.
List<Villager> toRemove = new ArrayList();
for(Villager e : tasked)
{
if(!e.hasTask())
{
toRemove.add(e);
}
}
tasked.removeAll(toRemove);
The Only issue with this approach, if the 'toRemove' list size is very large, you can do the opposite 'ls.retainAll(c)', by only identify what you want to keep.
If you are using java8 you can filter the list using stream API instead of iterating over it by hand.
List<Villager> villagersWithTask = tasked.stream().filter(e -> e.hasTask()).collect(Collectors.toList());

FindBugs warning: Inefficient use of keySet iterator

This a a similar question to [FindBugs warning: Inefficient use of keySet iterator instead of entrySet iterator
However, there I am trying to do something a little different. My current code is here:
for (Double key2 : sortedPolygons.keySet()) {
if (sortedPolygons.get(key2).getExteriorRing().equals(hole)) {
sortedPolygons.remove(key2);
break;
}
}
Doing something like the solution in the link does not work. Here is an implementation of said solution:
for(Map.Entry<Double, Polygon> entry : sortedPolygons.entrySet()) {
if (entry.getValue().getExteriorRing().equals(hole)) {
.....
The problem here is that I am trying to delete the entry. There is no entry.remove(). How can I replace my first block of code, without the FindBugs error:
Inefficient use of keySet iterator instead of entrySet iterator ->
This method accesses the value of a Map entry, using a key that was
retrieved from a keySet iterator. It is more efficient to use an
iterator on the entrySet of the map, to avoid the Map.get(key) lookup.
To note, the underlying structure is TreeMap, and it cannot be changed.
I fail to understand your reasoning: in the first snippet, you use
sortedPolygons.remove(key2);
to remove a key. Nothing prevents you to do the same in the second snippet:
sortedPolygons.remove(entry.getKey());
Whatever the way you iterate, this will lead to a ConcurrentModificationException anyway, because for most collections, you can't modify it while iterating on it, except by using its iterator.
Quote from the javadoc:
The iterators returned by the iterator method of the collections returned by all of this class's "collection view methods" are fail-fast: if the map is structurally modified at any time after the iterator is created, in any way except through the iterator's own remove method, the iterator will throw a ConcurrentModificationException.
So the code should be:
for (Iterator<Map.Entry<Double, Polygon>> it = sortedPolygons.entrySet().iterator(); it.hasNext(); ) {
Map.Entry<Double, Polygon> entry = it.next();
if (entry.getValue().getExteriorRing().equals(hole)) {
it.remove();
// if you want to exit the loop as soon as you found a match:
break;
}
}
How about you use the entrySet() iterator as suggested.
for(Iterator<Map.Entry<Double, Ploygon>> iter = sortedPolygons.entrySet().iterator();
iter.hasNext();) {
Map.Entry<Double, Ploygon> entry = iter.next();
if (condition)
iter.remove();
}
However you don't need the key so you can just iterate the values
for(Iterator<Ploygon> iter = sortedPolygons.values().iterator();
iter.hasNext();) {
Ploygon ploygon = iter.next();
if (condition)
iter.remove();
}

iterator returning random letters can't get it to iterate

I have this iterator,
Set<BigFraction> key = knowledgeD.keySet();
TreeSet<BigFraction> sortKey = new TreeSet<BigFraction>();
sortKey.addAll(key);
Iterator<BigFraction> iter = sortKey.iterator();
return iter;
BigFraction is just the data type if it makes it any easier just sub this with int or something.
Anyway when i called the iterator later on to
while (iterator().hasNext());
It basically just gives me an infinite loop of somesort... and when i printout iterator() before this while loop i get
java.util.TreeMap$KeyIterator#53b4b24d
Any idea's kind of stuck,
Regards,
Sim
You need to use your Iterator like this:-
while (iter.hasNext()) {
System.out.println(iter.next()); //Do whatever you want
}
where hasNext() tells if the iterator has more values or not, and next() returns the next value in the iterator.
Also, the explanation of why your current iterator loop is not working(going into an infinite loop), has been explained by #jacobm.
iterator().hasNext() never advances the iterator, it just checks to see if it has an element. So while (iterator().hasNext()); will always infinite-loop if there are any values to iterate over. You can fix it with:
Iterator<BigFraction> it = iterator();
while (it.hasNext()) {
it.next();
}
The call to iterator() constructs a new iterator, so your code will construct a new iterator each time through the loop. Instead try something like:
Iterator it = iter;
while (it.hasNext()) {
it.next()
}
Be sure to call next() each time through the loop, otherwise you won't increment the iterator, and it will just stay on the first item.
Iterator#hasNext returns true if the iteration has more elements, it does not return the next element in the iteration. which Iterator#next does.
If you use itarator if you must call iterator#next to get the next element of collection, but hasNext is operation is optional.
you could either write -
while (iter.hasNext()) {
Object oj = iter.next();
}
or
Object obj = null;
while ( (obj = iter.next())!=null) {
....
}
with this approach hashNext is not at all required.

Categories