I have a real-time program that runs a continuous while loop...
example:
while(true)
{
}
Inside that loop I have a for(MyObject o: myobjects) loop. When I run my code I see that every iteration of the while loop a new iterator is created to loop over my LinkedList called myobjects
What is a better way of iterating over a LinkedList without having Java create a ListIterator every time?
New iterator is given out by design. Read this. It gives you a new iterator every time you call iterator() method and it doesn't maintain states.
Code for the iterator :
public ListIterator<E> listIterator(final int index) {
rangeCheckForAdd(index);
return new ListItr(index);
}
What is a better way of iterating over a LinkedList without having Java create a ListIterator every time?
"Better" is very situational. You should consider whether the behavior you have now is actually a problem, because what you describe is about the simplest Java code for the job.
If you do need to iterate specifically over a LinkedList (as opposed, say, to an ArrayList), and you want to do so without creating a new ListIterator every time, then your best bet is probably to create a single ListIterator up front, and reuse it at every iteration:
ListIterator<MyObject> iterator = myobjects.listIterator();
while (true) {
// Return to the beginning of the list:
while (iterator.hasPrevious()) {
iterator.previous();
}
// The desired iteration:
while (iterator.hasNext()) {
MyObject o = iterator.next();
// do something with o
}
}
Do be aware, however, that this opens you up to trouble if the underlying list is modified. Any such modification will invalidate the ListIterator (its methods should start throwing ConcurrentModificationExceptions). In your original code, that will affect just one iteration of the outer loop, but if you reuse the iterator then you may need different handling of that situation. If the list is modified elsewhere in the outer loop, then re-using the same iterator is right out.
On the other hand, if you could be sure that you have a RandomAccess list, such as an ArrayList, then you could reasonably avoid iterators altogether, and just iterate by index:
while (true) {
// The desired iteration:
for (int i = 0; i < myobjects.size(); i += 1) {
MyObject o = myobjects.get(i);
// do something with o
}
}
Do not do that if you have or may have a LinkedList, however, because it will increase the cost of the iteration from O(n) to O(n2) for LinkedLists and similar sequential-access lists.
The source code of LinkedList says a new iterator is being created. If your list is dynamic, you will need a new iterator as it will become stale.
But, I believe if your list is a constant, you are better off running a normal for loop.
`int length = myobjects.size();
for (int i=0; i < length; i++)
{
//access here
}`
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
I'm reading J. Bloch's "Effective Java" and now I'm at the section about for-each vs for-loop. He mentioned three cases where we couldn't use the for-each loop and one of them is the following:L
Parallel iteration— If you need to traverse multiple collections in
parallel, then you need explicit control over the iterator or index
variable, so that all iterators or index variables can be advanced in
lockstep (as demonstrated unintentionally in the buggy card and dice
examples above).
The case is not quite clear to me, I can't imagine an example.
The first thought that popped into my head was that it was just about iterating the same collection in multiple threads but it's probably not what he meant. I don't see any restrictions preventing us from doing so (read-only). Actually:
public class MyRunnable implements Runnable{
private Collection<String> col;
//CTOR ommmited
public void run(){
for(String s : col){
//print o, not modify
}
}
Then we just start some threads with the same instance. So, we're not afraid of getting ConcurrentModificationException (JavaDocs) because we perform read-only access, even by multiple threads simultaneously.
What's wrong?
I don't think he meant "in parallel" as in concurrently.
It is much simpler. Suppose you have two Collections and you want the same loop (not a nested loop) to iterate over both of them, taking the i'th element of each one in each iteration. You can't do that with the enhanced for loop, since it hides the indices and the iterator.
You must use the standard for loop (for ordered Collections) :
private List<String> one;
private List<String> two;
public void run(){
for(int i = 0; i<one.size() && i<two.size();i++){
// do something with one.get(i) and two.get(i)
}
}
Or explicit Iterators (for un-ordered Collections) :
private Set<String> one;
private Set<String> two;
public void run(){
for(Iterator<String> iterOne=one.iterator(),Iterator<String> iterTwo=two.iterator(); iterOne.hasNext()&&iterTwo.hasNext();){
// do something with iterOne.next() and iterTwo.next()
}
}
Parallel iteration— If you need to traverse multiple collections in
parallel, then you need explicit control over the iterator or index
variable, so that all iterators or index variables can be advanced in
lockstep (as demonstrated unintentionally in the buggy card and dice
examples above).
In plain English lockstep means at same time. It means you cannot iterate over more than one collection at same time using for-each. You will have to use separate iterators (
or for loop as shown by Eran) like below:
Iterator iterator1 = list1.iterator();
Iterator iterator2 = list2.iterator();
Iterator iterator3 = list3.iterator();
while (iterator1 .hasNext() && iterator2 .hasNext() && iterator3.hasNext()){
Item i1 = iterator1 .next();
Item i2 = iterator2 .next();
Item i3 = iterator3.next();
// rest of your code.
}
I need to iterate over a collection of items & sometimes add to that collection at the same time. However, incase I add while iterating then I just start the iteration from fresh by breaking out of iteration loop & restarting iteration from beginning. However this leads to
ConcurrentModificationException. [code below]
List<Integer> collection = new ArrayList<>();
for (Integer lobId: collection) {
..
if (someCondition) {
collection.add(something);
break;
}
}
How could I possibly do something like above avoiding ConcurrentModificationException?
Would it be correct to simply use an Array instead of ArrayList to avoid this exception ?
Is there any type of specialized collection for this ?
--
Edit:
I dont want to create a new copy for this arraylist because I'm repeating this entire iteration process multiple times unless some requirement is completed. Creating a new copy each time would bring in some extra overhead, which I would like to avoid if somehow possible.
Also if possible I would like to maintain a sorted order & unique values in that collection. Is there anything that is ready to use in any library? Otherwise I could sort it at the end of iteration process & remove duplicates. That will also do fine for me.
Use another collection for the additions and combine them at the end.
List<Integer> collection = new ArrayList<>();
collection.add(...)
...
List<Integer> tempCollection = new ArrayList<>();
for (Integer lobId: collection ) {
..
if (someCondition) {
tempCollection.add(something);
break;
}
}
collection.addAll(tempCollection);
This code cannot lead to ConcurrentModificationException because after you add an element you break the loop and dont use iterator anymore
if I understand you right, you want to iterate over the list , if some condition , you want to break the iteration , and an item and start fresh .
In the case do this:
List<Integer> collection = new ArrayList<>();
boolean flag = false;
Integer item =
for (Integer lobId: collection) {
..
if (someCondition) {
flag = true;
item = something;
break;
}
}
if (flag){
collection.add(item);
}
if someone else is going to change the list outside out loop - you will need to sync those access - read iterator thread safe , and use the other answers here like copying the list or some other copy on write
ConcurrentModificationException basically means that you're iterating over a Collection with one iterator (albeit implicitly defined by your enhanced for loop) and invalidating it on the fly by changing the Collection itself.
You can avoid this by doing the modifications via the sameiterator:
List<Integer> collection = new ArrayList<>();
ListIterator<Integer> iter = collection.listIterator();
while (iter.hasNext()) {
Integer currVal = iter.next();
if (someCondition) {
iter.add(something); // Note the addition is done on iter
break;
}
}
Don't use for each, use the good old
for(int i=0; i<collection.size();i++)
I'm just starting to work with lists in java. I'm wondering what the recommended method to modify each element of a list would be?
I've been able to get it done with both the following methods, but they both seem fairly unelegant. Is there any better way to get this done in java? And is any of the below methods recommended over the other, or are both on the same level?
//Modifying with foreach
for (String each : list)
{
list.set(list.indexOf(each), each+ " blah");
}
//Modifying with for
for (ListIterator<String> i = list.listIterator(); i.hasNext(); i.next())
{
i.next();
list.set(i.nextIndex()-1, i.previous() + " blah yadda");
}
The second version would be better. Internally they are the same in the end, but the second actually allows you to modify the list, while the first one will throw a ConcurrentModificationException.
But then you are using the Iterator in a wrong way. Here is how you do it correctly:
for (final ListIterator<String> i = list.listIterator(); i.hasNext();) {
final String element = i.next();
i.set(element + "yaddayadda");
}
The iterator is the one that needs to modify the list as it is the only one that knows how to do that properly without getting confused about the list elements and order.
Edit: Because I see this in all comments and the other answers:
Why you should not use list.get, list.set and list.size in a loop
There are many collections in the Java collections framework, each on optimized for specific needs. Many people use the ArrayList, which internally uses an array. This is fine as long as the amount of elements does not change much over time and has the special benefit that get, set and size are constant time operations on this specific type of list.
There are however other list types, where this is not true. For example if you have a list that constantly grows and/or shrinks, it is much better to use a LinkedList, because in contrast to the ArrayList add(element) is a constant time operation, but add(index, element), get(index) and remove(index) are not!
To get the position of the specific index, the list needs to be traversed from the first/last till the specific element is found. So if you do that in a loop, this is equal to the following pseudo-code:
for (int index = 0; index < list.size(); ++index) {
Element e = get( (for(int i = 0; i < size; ++i) { if (i == index) return element; else element = nextElement(); }) );
}
The Iterator is an abstract way to traverse a list and therefore it can ensure that the traversal is done in an optimal way for each list. Test show that there is little time difference between using an iterator and get(i) for an ArrayList, but a huge time difference (in favor for the iterator) on a LinkedList.
EDIT: If you know that size(), get(index) and set(index, value) are all constant time operations for the operations you're using (e.g. for ArrayList), I would personally just skip the iterators in this case:
for (int i = 0; i < list.size(); i++) {
list.set(i, list.get(i) + " blah");
}
Your first approach is inefficient and potentially incorrect (as indexOf may return the wrong value - it will return the first match). Your second approach is very confusing - the fact that you call next() twice and previous once makes it hard to understand in my view.
Any approach using List.set(index, value) will be inefficient for a list which doesn't have constant time indexed write access, of course. As TwoThe noted, using ListIterator.set(value) is much better. TwoThe's approach of using a ListIterator is a better general purpose approach.
That said, another alternative in many cases would be to change your design to project one list to another instead - either as a view or materially. When you're not changing the list, you don't need to worry about it.
Internally there in Iterator for for-each implementation. So there is no deference between these two cases. But if you trying to modify element it will throws ConcurrentModificationException.
I got mine working this way
String desiredInvoice="abc-123";
long desiredAmount=1500;
for (ListIterator<MyPurchase> it = input.getMyPurchaseList().listIterator(); it.hasNext();) {
MyPurchase item = it.next();
if (item.getInvoiceNo().equalsIgnoreCase(desiredInvoice)) {
item.setPaymentAmount(desiredAmount);
it.set(item);
break;
}
}
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 .