I cannot find out what this method does. Can someone please explain?
Example:
for (Iterator ite = list.iterator(); ite.hasNext(); )
Thanks, I just started learning java. Currently grade 9.
It's just "reading" the list with an iterator (useful if you want to remove elements from the list while reading).
You can get an element from the iterator with
Item item = ite.next();
if you want to remove the item from the list you can do simply
ite.remove();
You can loop a list also with simpler for, like
for (Item item : list) {
System.out.println(item.toString());
}
or
for (int i = 0; i<list.size(); i++) {
Item item = list.get(i);
System.out.println(item.toString());
}
but with these, if you try to do list.remove(item) or list.remove(i) you will raise an exception (ConcurrentModificationException if I'm not wrong).
At a very basic level, an iterator "walks through" the list until it gets to the end. So in that method, you're creating an object that points at one object in the list. When you call next() on the iterator, it moves to the next object in the list. And when you call hasNext() on the iterator, you're asking whether the iterator has anywhere else to go, or whether it's at the end of the list. hasNext() will return true if the iterator has a next() and false otherwise.
You likely want to create your for loop like this:
for ( Iterator iter = list.iterator(); iter.hasNext(); iter.next() )
which creates a new iterator for the list (the first element). Each time the loop comes back, it calls iter.next() which makes the iterator point to the next element in the list. When you've gotten to the end of the list, iter.hasNext() is no longer true, and so the loop breaks.
In short, you're just creating a for loop that goes through every element of the list.
Related
I'm trying to iterate a list, wherein each iteration I'm doing one of the below:
Continue to next element (by some logic)
Removing the current element
What I need is that after I'm iterating through all the items, it will continue to iterate until the list is empty (the logic ensures all elements will be removed).
Problem is that after the iterator iterates all the list elements, it didn't continue to run on the elements I didn't remove:
List<Integer> lst = new ArrayList();
lst.add(1);
lst.add(2);
lst.add(3);
Iteartor<Integer> iterator = lst.listIterator();
while (iterator.hasNext()){
Integer curInt = iterator.next();
if (!passTest(curInt)){
continue;
}
iterator.remove();
}
IMPORTANT NOTE: passTest(curInt) logic can be different for each iteration. It means that iteration one can cause continue, then the second and third iterations will cause a removal. PROBLEM is I'm expecting for a fourth iteration (on the first item that wasn't removed).
The solution I've found:
List<Integer> lst = new ArrayList();
lst.add(1);
lst.add(2);
lst.add(3);
Iteartor<Integer> iterator = lst.listIterator();
while (!lst.isEmpty()){
Integer curInt;
if (iteration.hasNext()){
curInt = iterator.next();
} else {
curInt = lst.get(0);
}
if (!passTest(curInt)){
continue;
}
iterator.remove();
}
Is that the right way to achieve that?
Your solution doesn't seem correct. You will first iterate over all the elements of the List, possibly removing some of them. Once you finish iterating over the List, iteration.hasNext() will always return false, so you'll keep getting the first element (due to curInt = lst.get(0)). If you remove that first element, you'll get a different element the next time curInt = lst.get(0) is executed, so the List will become empty in the end, but that doesn't seem like the desired behavior (if it was the desired behavior, you could eliminate the Iterator and just keep getting the first element in a loop and possibly removing it).
You should use nested loops, and re-create the Iterator instance inside the outer loop:
while (!lst.isEmpty()) {
Iteartor<Integer> iterator = lst.listIterator();
while (iterator.hasNext()) {
Integer curInt = iterator.next();
if (passTest(curInt)) {
iterator.remove();
}
}
}
Each iteration of the outer loop creates an Iterator and performs the inner loop.
Each iteration of the inner loop iterates over the elements of the List, and possibly removes some of them.
Once you finish an iteration over the List, you must create a new Iterator in order to iterate over the remaining elements again.
I have a very basic question.
I have created simple ArrayList and I am removing the item while iterating using for-each loop. It gives me java.util.ConcurrentModificationException because I can't remove an item while iterating but when I un-comment the if condition it works fine.
Please can anybody explain me how for-each works in this way.
ArrayList<String> list1 = new ArrayList<String>();
list1.add("Hello");
list1.add("World");
list1.add("Good Evening");
for (String s : list1) {
//if (s.equals("World")) {
list1.remove(1);
//}
}
If I change it to list1.remove(2); or list1.remove(0); then also its working fine.
Note: This is sample code and I know it will work fine using Iterator. My sole purpose of this question is to know how method remove() works perfectly if condition is un-commented no matter what index you are removing from the list.
The list has a variable called modCount, which means "modification count". Whenever you call remove (or perform other structural modifications), it increments the modCount.
The iterator can't keep track of its position in the list if you are adding or removing elements without telling the iterator. So as a safety check, at the start of iteration, the iterator makes a note of the modCount, saving it as expectedModCount. When each item is read from the iterator, the iterator checks to make sure the modCount still equals the expected value, and throws an exception if it doesn't.
Usually, this will successfully cause the exception to be thrown if the list is unsafely modified during iteration. However, it's not sufficient in this case when the if statement is enabled. After your code has read "World", that item is removed, and so the list now contains ["Hello", Good Evening"]. The iterator is still at position 1 (which now contains "Good Evening") and when it tries to read the next item, it finds it has now reached the end of the list, so it doesn't bother to check the modCount. Hence, no exception.
Note the caveat in the ConcurrentModificationException documentation: "It is, generally speaking, impossible to make any hard guarantees in the presence of unsynchronized concurrent modification. Fail-fast operations throw ConcurrentModificationException on a best-effort basis."
Even if it doesn't happen to throw the exception in this case, the code is still wrong. To remove an element while iterating, you must use the iterator's own remove method:
for (Iterator<String> it = list1.iterator(); it.hasNext();) {
String s = it.next();
if (s.equals("World")) {
it.remove();
}
}
That way, the iterator knows that the list has changed and can still iterate correctly.
Alternatively, you can iterate from a temporary copy of the list:
for (String s : new ArrayList<>(list1)) {
if (s.equals("World")) {
list1.remove(...);
}
}
Although, in this simple case, you don't even need to do that; you can just write:
list1.remove("World");
You can also use an index-based removal. The drawback of this solution is that the list1.size() gets evaluated during every loop iteration. The positive thing is that removing an item from a List by its index is faster.
for (int i = 0; i < list1.size(); /* i incremented in loop body */) {
if ("World".equals(list1.get(i))) {
list1.remove(i);
}
else {
i++;
}
}
Use an Iterator and call remove():
Iterator<String> iter = list1.iterator();
while (iter.hasNext()) {
String str = iter.next();
if (someCondition)
iter.remove();
}
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.
package wrap;
import java.util.*;
public class ArrayListDemo {
public static void main(String [] args){
ArrayList<String> a=new ArrayList<String>();
a.add("B");
a.add("C");
a.add("D");
ListIterator<String> i=a.listIterator();
while(i.hasPrevious()){
System.out.println(i.previous());
}
}
}
The program works fine for hasNext() and next() methods but for hasPrevious() and previous() it displays a message as below::
<terminated> ArrayListDemo [Java Application] C:\Program Files (x86)\Java\jre7\bin\javaw.exe (28-Oct-2013 3:20:35 PM)
From the doc :
public ListIterator<E> listIterator()
Returns a list iterator over the elements in this list (in proper
sequence).
and
boolean hasPrevious()
Returns true if this list iterator has more elements when traversing
the list in the reverse direction.
Because the iterator is in the first position, hasPrevious() will return false and hence the while loop is not executed.
a's elements
"B" "C" "D"
^
|
Iterator is in first position so there is no previous element
If you do :
ListIterator<String> i=a.listIterator(); <- in first position
i.next(); <- move the iterator to the second position
while(i.hasPrevious()){
System.out.println(i.previous());
}
It will print "B" because you're in the following situation :
a's elements
"B" "C" "D"
^
|
Iterator is in second position so the previous element is "B"
You could also use the method listIterator(int index). It allows you to place the iterator at the position defined by index.
If you do :
ListIterator<String> i=a.listIterator(a.size());
It will print
D
C
B
Since you get the default ListIterator for the list, it starts with the first element, which is why hasPrevious() returns false and the while loop is exited. If you want to traverse the list in the reverse order, get the ListIterator from the last index and traverse backwards using the hasPrevious() and previous() methods.
ListIterator<String> i = a.listIterator(a.size()); // Get the list iterator from the last index
while (i.hasPrevious()) {
System.out.println(i.previous());
}
ListIterator<String> i=a.listIterator();
initially iterator i will point to index of 0
You are at index 0 so there is no previous element.
It will start at the front of the list and thus nothing is before that point. If you want to use these methods, use a ListIterator.
Docs.
You gave to reach to the end of the list or anywhere in between to traverse back. There is no previous element to element at index 0.
Eg
System.out.println("Elements in forward directiton");
while(i.hasNext()){
System.out.println(i.next());
}
System.out.println("Elements in backward directiton");
while(i.hasPrevious()){
System.out.println(i.previous());
}
As said by others, You pointer is still pointing to first element in List so -1 is not possible.
List of size n will have 1,2 ....n-1 as index.
n-1 is not -1.
THis is the reason why hasPrevious and previous are not working for you.
Cheers.
I'm iterating a java.util.LinkedList and in some cases I add an element to it.
LinkedList<Schedule> queue = new LinkedList<Schedule>(schedules);
ListIterator<Schedule> iterator = queue.listIterator();
while (iterator.hasNext()) {
Schedule schedule = iterator.next();
if(condition)
iterator.add(new Schedule());
}
The problem is that if I start for example with one item, the new item is added before the next iterator.next() call and the iteration exits.
How can I append the item at the end of the LinkedList while iterating?
Please don't tell me to use another list and iterate it after the first because it doesn't solve my problem correctly.
Assuming you don't have a hard requirement to use an iterator then you can just shelve it and 'iterate' over the list by index instead:
LinkedList<Schedule> list;
for (int i = 0; i < list.size(); i++) {
final Schedule schedule = list.get(i);
if(condition)
list.add(new Schedule());
}
If you cannot use another list, you could solve your problem by keeping a count of the number of elements you processed via the iterator and compare that to the original size of the list: all new element will be at the end of the list, so you can end your loop when you have reached the original size.
LinkedList<Schedule> queue = new LinkedList<Schedule>(schedules);
int origSize = queue.size();
int currCount = 0;
ListIterator<Schedule> iterator = queue.listIterator();
while (iterator.hasNext()) {
++currCount;
if (currCount >= origSize) {
break; // reached the end of the original collection
}
Schedule schedule = iterator.next();
if(condition)
iterator.add(new Schedule());
}
You could also use an extra list to keep track of the new elements and add that to the original list after the processing is over:
LinkedList<Schedule> queue = new LinkedList<Schedule>(schedules);
LinkedList<Schedule> addQueue = new LinkedList<Schedule>();
ListIterator<Schedule> iterator = queue.listIterator();
while (iterator.hasNext()) {
Schedule schedule = iterator.next();
if(condition)
addQueue.add(new Schedule());
}
queue.addAll(addQueue);
Also, note that iterator.add()
Inserts the specified element into the list (optional operation). The element is inserted immediately before the next element that would be returned by next, if any, and after the next element that would be returned by previous, if any. (If the list contains no elements, the new element becomes the sole element on the list.) The new element is inserted before the implicit cursor: a subsequent call to next would be unaffected, and a subsequent call to previous would return the new element. (This call increases by one the value that would be returned by a call to nextIndex or previousIndex.)
so if you have more than one elements in the list, it will not add the new ones to the end, but between the current one and the one returned by next(). If you indeed want to place the new elements at the end of the list, use queue.add(...)
In general, it is not advisable to modify a collection while traversing it via an iterator, so I suggest you use the second approach (collect the extra elements in a separate list and add them to the original at the end)
As others have suggested, there is no efficient, off-the-shelf support for end-insertion during iteration in the current Collections framework. One suggestion involved rewriting the iterator. But I say, why not go a couple steps further?
Use reflection to modify the accessibility of the Node class, which gives you references to the double links, so you don't need to start iteration over with get(index), which should not be used in performant code.
Inherit/derive from LinkedList and override judiciously.
This is a no-brainer, but in the same spirit as 2 above, since the JDK is open-source, borrow the source as needed and write your own implementation.
In either case, I really feel this feature should be provided by Java LinkedList API.
How can I append the item at the end of the LinkedList while
iterating?
public void addWork(Scheduler scheduler)
{
synchronized(scheduler)
{
queue.addLast(scheduler);
}
}
and you can use queue.removeFirst() to deal with item in the queue from top-to-down.
public synchronized Scheduler getWork()
{
return queue.removeFirst();
}
Edited.
The requirements to add while iterating and include the added items in the iteration can only be met if you don't use an iterator for iteration since there is no way to recompute the state of your iterator every time an element is added. If you accept the less efficient get method to do your iteration, the problem is trivial. For example
LinkedList<Schedule> queue = new LinkedList<Schedule>(){{add(new Schedule());add(new Schedule());add(new Schedule());}};
int i = 0;
// queue.size() is evaluated every iteration
while (i < queue.size()) {
Schedule schedule = queue.get(i);
if(i++ % 2 == 0)
queue.add(new Schedule());
}
System.out.println(queue.size());
prints 6 as expected.