Is it advisable not to use iterator.hasNext() in looping over an iterator?
For example I would like to set value obj to each element of a list. I could use the following code or make it more readable by using hasNext() in a loop.
int size = list.size();
ListIterator<? super T> itr = list.listIterator();
for (int i=0; i<size; i++) {
itr.next();
itr.set(obj);
}
Instead of these lines I could write my code like the following.
for (ListIterator<? super T> itr = list.listIterator(); itr.hasNext(); ) {
itr.next();
itr.set(obj);
}
Is it advisable not to use iterator.hasNext() in looping over an iterator?
Um, no. hasNext is the standard way you iterate with an iterator. That's what the enhanced-for statement does behind the scenes for an iterable, for example.
Having said that, your code is already ListIterator-specific, as you're using ListIterator.set - so your second block of code won't actually compile at the moment. Even if it did, it wouldn't work, as you still need to call next(). This would work though:
for (ListIterator<? super T> itr = list.listIterator(); itr.hasNext(); ) {
itr.next();
itr.set(obj);
}
Well, when NetBeans refactor you for-each loop to use of iterators, they do it in following way.
for-each:
for (T object : list) {
}
iterator pattern:
for (Iterator<T> it = list.iterator(); it.hasNext();) {
T object = it.next();
}
I think it is totally okay to use hasNext() on iterator while iterating.
There is no such recommendation not to use hasNext.
The Iterator API list has just three methods, add, remove and hasNext
Also from clean code the second approach looks far better then the first one.
When using an iterator, you should always call the hasNext() method. Otherwise, you may run into a NoSuchElementException when calling the next() method.
Of course, you should use hasNext(), but only for iterating over a collection, not for populating the collection. To fill the collection, work on the collection itself, not on it's iterator and to read from the collection use the for loop as described by #JMelnik.
Fill the collection
Collection<MyObject> list = ...;
while (something) {
list.add(myObject);
}
Read the collection
for (MyObject myObject : list) {
...
}
Related
This question already has answers here:
Iterating through a Collection, avoiding ConcurrentModificationException when removing objects in a loop
(31 answers)
Closed 8 years ago.
I'm trying to remove some elements from an ArrayList while iterating it like this:
for (String str : myArrayList) {
if (someCondition) {
myArrayList.remove(str);
}
}
Of course, I get a ConcurrentModificationException when trying to remove items from the list at the same time when iterating myArrayList. Is there some simple solution to solve this problem?
Use an Iterator and call remove():
Iterator<String> iter = myArrayList.iterator();
while (iter.hasNext()) {
String str = iter.next();
if (someCondition)
iter.remove();
}
As an alternative to everyone else's answers I've always done something like this:
List<String> toRemove = new ArrayList<String>();
for (String str : myArrayList) {
if (someCondition) {
toRemove.add(str);
}
}
myArrayList.removeAll(toRemove);
This will avoid you having to deal with the iterator directly, but requires another list. I've always preferred this route for whatever reason.
Java 8 user can do that: list.removeIf(...)
List<String> list = new ArrayList<>(Arrays.asList("a", "b", "c"));
list.removeIf(e -> (someCondition));
It will remove elements in the list, for which someCondition is satisfied
You have to use the iterator's remove() method, which means no enhanced for loop:
for (final Iterator iterator = myArrayList.iterator(); iterator.hasNext(); ) {
iterator.next();
if (someCondition) {
iterator.remove();
}
}
No, no, NO!
In single threated tasks you don't need to use Iterator, moreover, CopyOnWriteArrayList (due to performance hit).
Solution is much simpler: try to use canonical for loop instead of for-each loop.
According to Java copyright owners (some years ago Sun, now Oracle) for-each loop guide, it uses iterator to walk through collection and just hides it to make code looks better. But, unfortunately as we can see, it produced more problems than profits, otherwise this topic would not arise.
For example, this code will lead to java.util.ConcurrentModificationException when entering next iteration on modified ArrayList:
// process collection
for (SomeClass currElement: testList) {
SomeClass founDuplicate = findDuplicates(currElement);
if (founDuplicate != null) {
uniqueTestList.add(founDuplicate);
testList.remove(testList.indexOf(currElement));
}
}
But following code works just fine:
// process collection
for (int i = 0; i < testList.size(); i++) {
SomeClass currElement = testList.get(i);
SomeClass founDuplicate = findDuplicates(currElement);
if (founDuplicate != null) {
uniqueTestList.add(founDuplicate);
testList.remove(testList.indexOf(currElement));
i--; //to avoid skipping of shifted element
}
}
So, try to use indexing approach for iterating over collections and avoid for-each loop, as they are not equivalent!
For-each loop uses some internal iterators, which check collection modification and throw ConcurrentModificationException exception. To confirm this, take a closer look at the printed stack trace when using first example that I've posted:
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372)
at java.util.AbstractList$Itr.next(AbstractList.java:343)
at TestFail.main(TestFail.java:43)
For multithreading use corresponding multitask approaches (like synchronized keyword).
While other suggested solutions work, If you really want the solution to be made thread safe you should replace ArrayList with CopyOnWriteArrayList
//List<String> s = new ArrayList<>(); //Will throw exception
List<String> s = new CopyOnWriteArrayList<>();
s.add("B");
Iterator<String> it = s.iterator();
s.add("A");
//Below removes only "B" from List
while (it.hasNext()) {
s.remove(it.next());
}
System.out.println(s);
If you want to modify your List during traversal, then you need to use the Iterator. And then you can use iterator.remove() to remove the elements during traversal.
List myArrayList = Collections.synchronizedList(new ArrayList());
//add your elements
myArrayList.add();
myArrayList.add();
myArrayList.add();
synchronized(myArrayList) {
Iterator i = myArrayList.iterator();
while (i.hasNext()){
Object object = i.next();
}
}
One alternative method is convert your List to array, iterate them and remove them directly from the List based on your logic.
List<String> myList = new ArrayList<String>(); // You can use either list or set
myList.add("abc");
myList.add("abcd");
myList.add("abcde");
myList.add("abcdef");
myList.add("abcdefg");
Object[] obj = myList.toArray();
for(Object o:obj) {
if(condition)
myList.remove(o.toString());
}
You can use the iterator remove() function to remove the object from underlying collection object. But in this case you can remove the same object and not any other object from the list.
from here
This question already has answers here:
Iterating through a Collection, avoiding ConcurrentModificationException when removing objects in a loop
(31 answers)
Closed 8 years ago.
I'm trying to remove some elements from an ArrayList while iterating it like this:
for (String str : myArrayList) {
if (someCondition) {
myArrayList.remove(str);
}
}
Of course, I get a ConcurrentModificationException when trying to remove items from the list at the same time when iterating myArrayList. Is there some simple solution to solve this problem?
Use an Iterator and call remove():
Iterator<String> iter = myArrayList.iterator();
while (iter.hasNext()) {
String str = iter.next();
if (someCondition)
iter.remove();
}
As an alternative to everyone else's answers I've always done something like this:
List<String> toRemove = new ArrayList<String>();
for (String str : myArrayList) {
if (someCondition) {
toRemove.add(str);
}
}
myArrayList.removeAll(toRemove);
This will avoid you having to deal with the iterator directly, but requires another list. I've always preferred this route for whatever reason.
Java 8 user can do that: list.removeIf(...)
List<String> list = new ArrayList<>(Arrays.asList("a", "b", "c"));
list.removeIf(e -> (someCondition));
It will remove elements in the list, for which someCondition is satisfied
You have to use the iterator's remove() method, which means no enhanced for loop:
for (final Iterator iterator = myArrayList.iterator(); iterator.hasNext(); ) {
iterator.next();
if (someCondition) {
iterator.remove();
}
}
No, no, NO!
In single threated tasks you don't need to use Iterator, moreover, CopyOnWriteArrayList (due to performance hit).
Solution is much simpler: try to use canonical for loop instead of for-each loop.
According to Java copyright owners (some years ago Sun, now Oracle) for-each loop guide, it uses iterator to walk through collection and just hides it to make code looks better. But, unfortunately as we can see, it produced more problems than profits, otherwise this topic would not arise.
For example, this code will lead to java.util.ConcurrentModificationException when entering next iteration on modified ArrayList:
// process collection
for (SomeClass currElement: testList) {
SomeClass founDuplicate = findDuplicates(currElement);
if (founDuplicate != null) {
uniqueTestList.add(founDuplicate);
testList.remove(testList.indexOf(currElement));
}
}
But following code works just fine:
// process collection
for (int i = 0; i < testList.size(); i++) {
SomeClass currElement = testList.get(i);
SomeClass founDuplicate = findDuplicates(currElement);
if (founDuplicate != null) {
uniqueTestList.add(founDuplicate);
testList.remove(testList.indexOf(currElement));
i--; //to avoid skipping of shifted element
}
}
So, try to use indexing approach for iterating over collections and avoid for-each loop, as they are not equivalent!
For-each loop uses some internal iterators, which check collection modification and throw ConcurrentModificationException exception. To confirm this, take a closer look at the printed stack trace when using first example that I've posted:
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372)
at java.util.AbstractList$Itr.next(AbstractList.java:343)
at TestFail.main(TestFail.java:43)
For multithreading use corresponding multitask approaches (like synchronized keyword).
While other suggested solutions work, If you really want the solution to be made thread safe you should replace ArrayList with CopyOnWriteArrayList
//List<String> s = new ArrayList<>(); //Will throw exception
List<String> s = new CopyOnWriteArrayList<>();
s.add("B");
Iterator<String> it = s.iterator();
s.add("A");
//Below removes only "B" from List
while (it.hasNext()) {
s.remove(it.next());
}
System.out.println(s);
If you want to modify your List during traversal, then you need to use the Iterator. And then you can use iterator.remove() to remove the elements during traversal.
List myArrayList = Collections.synchronizedList(new ArrayList());
//add your elements
myArrayList.add();
myArrayList.add();
myArrayList.add();
synchronized(myArrayList) {
Iterator i = myArrayList.iterator();
while (i.hasNext()){
Object object = i.next();
}
}
One alternative method is convert your List to array, iterate them and remove them directly from the List based on your logic.
List<String> myList = new ArrayList<String>(); // You can use either list or set
myList.add("abc");
myList.add("abcd");
myList.add("abcde");
myList.add("abcdef");
myList.add("abcdefg");
Object[] obj = myList.toArray();
for(Object o:obj) {
if(condition)
myList.remove(o.toString());
}
You can use the iterator remove() function to remove the object from underlying collection object. But in this case you can remove the same object and not any other object from the list.
from here
I need to iterate all the elements of ArrayList except the last one. So I want to create such iterator. But I don't what to implement the whole iterator, I need to override only the hasNext() method, so I would like to subclass a "standard" iterator. Is there any way to do that?
I think the better way to do that rather than overriding the default iterator is to iterate the ArrayList on your own. An ArrayListhas a couple of method defined that can help you accomplish the task: get(int) and size().
Everything you have to do is to get the total number of elements in the ArrayList(with size()) and then loop through the elements accessing each element directly in each iteration using the get() method. Your code would look something like this:
for(int i = 0; i < myList.size() - 1; i++){
element = myList.get(i);
//do something
}
Now with this principle in mind, you may create your own class to iterate the ArrayList.
It would be odd to modify the iterator to perform this traversal. The obvious thing to do is to write the "algorithm" as you want it:
public static <T> void eachExceptLast(List<? extends T> list, Operation<T> op) {
Iterator<T> iter = list.iterator();
if (!iter.hasNext()) {
return;
}
T item = iter.next();
while (iter.hasNext()) {
op.run(item);
item = iter.next();
}
}
(Or use an index assuming a RandomAccess list.)
However, there's a much better way of doing this. list.subList(0, list.size()-1) (for a non-empty list) will return a view of the original list less the last element. It doesn't do a copy, and you can even use Iterator.remove.
You can create a class that implements either the Iterator or ListIterator interfaces and then override the hasNext() method .
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.
For example, for a list {1,2,3,4}, I must compare the pairs (1,2), (1,3), (1,4), (2,3), (2,4), (3,4). The way with normal for loops is:
for(i=0 ; i<list.size() ; i++){
for(j=i+1 ; j<list.size() ; j++){
//do stuff with list[i] and list[j];
}
}
Can I do something like this with iterators (see below)?
for (int i : list){
for(int j : [list after index i]){
//do stuff with list[i] and list[j];
}
}
Maybe not that elegant, but possible:
int lastIndex = list.size()-1;
for (Object i : list) {
for (Object j : list.sublist(list.indexOf(i), list.size()-1)) {
// do what has to be done
}
}
Since the index of the items is clearly important here, I think you should stick with the old index-based for loop in this case. It might not be quite as pretty, but it will be explicit.
If you're doing this a lot you could encapsulate the code in a method and pass it a method to invoke per-pair.
This still uses nested loops, but uses a ListIterator instead.
A ListIterator can be obtained through the listIterator(idx) method of the List interface. Its not really more elegant than the for loop but might perform better if the list is not randomly accessible, for example a LinkedList.
for (ListIterator i=list.listIterator(); i.hasNext(); ) {
Object a = i.next();
for (Iterator j=list.listIterator(i.previousIndex()); j.hasNext(); ) {
Object b = j.next();
}
}
You can implement your own Iterator to do this. You'll also have to create a simple wrapper objects to let you return two items at once (it is very annoying that there is no tuple type built in to Java!).
Simply by implementing the Iterator however will not let you use it directly in a for loop. You'll have to do something like this instead:
Iterator<MyPairObject> iterator = new MyIterator(list);
while (iterator.hasNext()) {
...
}
However, if you subclass the list class you're using you can override the iterator() method and return your own iterator - then you'll be able to use your custom list class and it's iterator directly in a for loop.