what is the best way of iterate a arraylist [duplicate] - java

This question already has answers here:
Java: Best way to iterate through a Collection (here ArrayList)
(6 answers)
Closed 7 years ago.
i have these five way to iterate through ArrayList and these are
public static void main(String[] argv) {
// create list
List<String> aList = new ArrayList<String>();
// add 4 different values to list
aList.add("eBay");
aList.add("Paypal");
aList.add("Google");
aList.add("Yahoo");
// iterate via "for loop"
System.out.println("==> For Loop Example.");
for (int i = 0; i < aList.size(); i++) {
System.out.println(aList.get(i));
}
// iterate via "New way to loop"
System.out.println("\n==> Advance For Loop Example..");
for (String temp : aList) {
System.out.println(temp);
}
// iterate via "iterator loop"
System.out.println("\n==> Iterator Example...");
Iterator<String> aIterator = aList.iterator();
while (aIterator.hasNext()) {
System.out.println(aIterator.next());
}
// iterate via "while loop"
System.out.println("\n==> While Loop Example....");
int i = 0;
while (i < aList.size()) {
System.out.println(aList.get(i));
i++;
}
// collection stream() util: Returns a sequential Stream with this collection as its source
System.out.println("\n==> collection stream() util....");
aList.forEach((temp) -> {
System.out.println(temp);
});
}
My question is iterating thru any of these way is same or there is any difference? if they, then which is the best way of doing this, my requirement is removing a element from an arraylist based on some condition.

my requirement is removing a element from an arraylist based on some condition
If you have to remove an element from the ArrayList while iterating over it, using an explicit iterator is the base way (your 3rd option). Use aIterator.remove() to remove the current element.
The enhanced for loop and forEach don't allow you to remove elements, since you don't have an index of the current element, and even if you did, removing an element inside the enhanced for loop will throw ConcurrentModificationException.
The regular for loop and the while loop also allow you to remove elements, since you have the index of the current element, but you should remember to decrement the index after removing an element, since removing an element from an ArrayList shifts all the elements that come after that element to the left.

Also, you can use this extension of ArrayList CopyOnWriteArrayList
http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/CopyOnWriteArrayList.html
Its threadsafe and you can do .remove without any problem, at cost of performance comparing with normal ArrayList.

Related

Deleting random elements of a list while going through the list

From what I read, it is safe to remove elements while iterating through a list. (instead of using the simple for each loop).
Suppose I have a list of elements, and I want to visit all of the elements, but while I visit each element, I will visit its neighbours (note that I have a map for each element which will give me its neighbours), thus I will
have to remove other elements from the original list. Thus I cannot use
iterator.remove().
What is a good way to do this, that is to say, remove elements from the list that I am going through without being at the position with the iterator?
One idea I had was the following, have my elements in a map, with value as
a boolean, (true for visited, and false otherwise).
Thus, I go through my list, and for each element i set it visited true, and if one if its neighbours I also see while visiting that element, I will also set them as true.
Use a for loop instead of a foreach to iterate over the items. Then remove as you see fit. Here is an example of removing even elements from the List
import java.util.List;
import java.util.ArrayList;
class Test {
public static void main(String[] args){
final List<Integer> ints = new ArrayList<Integer>();
ints.add(100);
ints.add(1);
ints.add(15);
ints.add(42);
ints.add(187);
System.out.println("Original List");
for(Integer i: ints){
System.out.println(i);
}
/* Remove any even elements from the list */
for(int i=0; i < ints.size(); i++){
if(ints.get(i) % 2 == 0){
ints.remove(i);
}
}
System.out.println("\nModified List");
for(Integer i: ints){
System.out.println(i);
}
}
}
Lets assume that you are talking about an input list that is an ArrayList.
The following approach will give you O(N) behaviour (for at least OpenJDK Java 6 through Java 8):
Create a HashSet.
Iterate over the elements of your input list:
Visit the element and add it to the set if it should be removed
Visit the neighbours of the element and add to the set any one that should be removed.
Call list.removeAll(set).
The removeAll method for ArrayList calls an internal batchRemove method (see here). This method performs a single pass over the ArrayList's backing array, removing elements and filling the holes. It tests each element to see if it should be removed by calling set.contains(elem). For a HashSet that test is O(1), and hence the removeAll(set) call is O(N) where N is the list size.
It is interesting to note that arrayList.removeAll(hashSet) will be O(N) where N is the list length, but removing the same elements like this:
for (Iterator it = arrayList.iterator; it.hasNext(); ) {
if (hashSet.contains(it.next())) {
it.remove();
}
}
will be O(NM) where N is the list length and M is the set size.

Why Looping through ArrayList<String> is same as a regular array? [duplicate]

This question already has answers here:
How does the Java 'for each' loop work?
(29 answers)
Closed 9 years ago.
Method 1
ArrayList<String> list = new ArrayList<String>();
for (String s : list) {
write.append(s);
write.append('\n');
}
How is looping through an ArrayList this way possible? isn't this method only applicable for static usual arrays, for example : String[] list2 = new String[]{"1","2","3","4"}; ?
If I want to loop over the ArrayList<String> list, why not doing this for example:
Method 2
for (int i = 0; i < list.size(); i++) {
write.append(list.get(i));
write.append("\n");
}
I'm just not understanding how is it possible to use Method 1. Any explanation is welcomed.
ArrayList implements Iterable which makes it provide an Iterator object, which is then user by for loop.
Any class implementing Iterable would be usable in a for loop, just like an array.
The simplified for loop is made to look same for arrays and collections, but under the hood, it uses index for arrays and iterator for collections.
These are called for-each loops, and can be applied to both arrays and collections. Format:
for ([type] [var-name] : [array or iterable value]) {
...
}
To use a for-each loop, you only need to satisfy one of two conditions:
The iteration value is an array, or
the iteration value is an Iterable.
The biggest reason we do this is because List isn't the only Iterable that we can use in the loop, but it is the only one that can be indexed. This allows you to do generic iteration instead of locking yourself into a fixed, indexed list format.
For example, HashSet is not ordered, but I can still iterate over it in a for-each loop:
HashSet<String> strs = new HashSet<String>();
for (String str : strs) { ... }
I can also have a method take an Iterable instead of a List:
public static void printStrings(Iterable<String> strs) {
for (String str : strs) {
System.out.println(str);
}
}
There is no way for me to iterate over it using an index without first copying it into something else, like an array or a List.
Another important reason to use the for-each loop is that it compiles to using the Iterator off the list (via Iterable.iterator()), which allows for fail-fast iteration. This results in things like ConcurrentModificationExceptions to tell us that the collection was modified while we were iterating over it. For example, this will always throw a ConcurrentModificationException:
List<String> strs = ... ;
for (String str : strs) {
strs.remove(str);
}
But this won't:
List<String> strs = ... ;
for (int i = 0; i < strs.length(); i++) {
strs.remove(str);
}
This is good for multi-threaded applications because you're supposed to lock the list before you access it since most List implementations aren't designed for thread-safety, and iteration is never thread-safe without external synchronization, both with indexing and with Iterator. If one thread is iterating over it while another changes it, this can (not guaranteed, but can) throw a ConcurrentModificationException, which tells you that the list isn't properly locked. The indexed for could never give you this kind of information. Instead, it will just exhibit strange behavior like skipping elements.
There is an interface called Iterable which allows fast iteration. If something implements Iterable, fast iteration is allowed. The Iterable interface has one method, which returns an Iterator which can be used to iterate the elements.
The first is called an enhanced-for, or "for each". It is considered syntactic sugar for the traditional model of for statements - allowing you to iterate over every element in a collection - be that an array or anything in the Java Collections Framework.
There are two distinct differences between these types of loops:
The enhanced for statement indexes the value for you, storing it in the temporary variable as part of the declaration. Thus, you don't have to do things like val[i] or value.get(i) - this happens for you automatically.
You don't get to specify what you increment by in the enhanced for statement; you either iterate over all elements in the collection, or you terminate early via a break statement.
The reason that this can be iterated over using a standard array is defined in the JLS, specifically §14.14.2 - since an array doesn't implement Iterable, it converts it to a standard-behaving for statement.
...Otherwise, the Expression necessarily has an array type, T[].
Let L1 ... Lm be the (possibly empty) sequence of labels immediately preceding the enhanced for statement.
The enhanced for statement is equivalent to a basic for statement of the form:
T[] #a = Expression;
L1: L2: ... Lm:
for (int #i = 0; #i < #a.length; #i++) {
VariableModifiers(opt) TargetType Identifier = #a[#i];
Statement
}
#a and #i are automatically generated identifiers that are distinct from any other identifiers (automatically generated or otherwise) that are in scope at the point where the enhanced for statement occurs.
This is the for-each syntax: http://docs.oracle.com/javase/1.5.0/docs/guide/language/foreach.html
The compiler will convert your code in method 1 to something like:
for (Iterator<String> iterator = list.iterator(); iterator.hasNext(); ) {
String s = iterator.next();
write.append(s);
write.append('\n');
}

Add elements to a List while iterating over it. (Java) [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Java: adding elements to a collection during iteration
My problem is that I want to expand a list with new elements while iterating over it and I want the iterator to continue with the elements that I just added.
From my understanding the ListIterator.add() adds an element before the current element in the list, not after it. Is it possible to achieve this in some other way?
You can't modify a Collection while iterating over it using an Iterator, except for Iterator.remove().
However, if you use the listIterator() method, which returns a ListIterator, and iterate over that you have more options to modify. From the javadoc for add():
The new element is inserted before the implicit cursor: ... a subsequent call to previous() would return the new element
Given that, this code should work to set the new element as the next in the iteration:
ListIterator<T> i;
i.add(e);
i.previous(); // returns e
i.previous(); // returns element before e, and e will be next
This will work except when the list starts iteration empty, in which case there will be no previous element. If that's a problem, you'll have to maintain a flag of some sort to indicate this edge case.
There might be some trick with ListIterator, but the easiest solution is probably an old style index loop. Verify performance isn't an issue (no linked lists - but ArrayList is fine).
List<Object> myList;
for(int i = 0; i < myList.size(); i++)
{
Object current = myList.get(i);
// Anything you insert after i will be discovered during next iterations
}
How about
List<Foo> fooList = getFooList();
List<Foo> tempFooList = new ArrayList<Foo>()
for(Foo f : fooList)
{
...
// add items that need to be added to temp
tempFooList.add(new Foo());
...
}
fooList.addAll(tempFooList);

Getting a ConcurrentModificationException thrown when removing an element from a java.util.List during list iteration? [duplicate]

This question already has answers here:
Iterating through a Collection, avoiding ConcurrentModificationException when removing objects in a loop
(31 answers)
Closed 5 years ago.
#Test
public void testListCur(){
List<String> li=new ArrayList<String>();
for(int i=0;i<10;i++){
li.add("str"+i);
}
for(String st:li){
if(st.equalsIgnoreCase("str3"))
li.remove("str3");
}
System.out.println(li);
}
When I run this code,I will throw a ConcurrentModificationException.
It looks as though when I remove the specified element from the list, the list does not know its size have been changed.
I'm wondering if this is a common problem with collections and removing elements?
I believe this is the purpose behind the Iterator.remove() method, to be able to remove an element from the collection while iterating.
For example:
Iterator<String> iter = li.iterator();
while(iter.hasNext()){
if(iter.next().equalsIgnoreCase("str3"))
iter.remove();
}
The Java 8 way to remove it from the List without Iterator is:
li.removeIf(<predicate>)
i.e.
List<String> li = new ArrayList<String>();
// ...
li.removeIf(st -> !st.equalsIgnoreCase("str3"));
Note that this exception does not always indicate that an object has been concurrently modified by a different thread. If a single thread issues a sequence of method invocations that violates the contract of an object, the object may throw this exception. For example, if a thread modifies a collection directly while it is iterating over the collection with a fail-fast iterator, the iterator will thow this exception
Taken from http://download.oracle.com/javase/1.4.2/docs/api/java/util/ConcurrentModificationException.html
yes people run into it -- the problem is you can't modify the list while iterating over it. I have used 2 alternatives in the past:
You can keep track of the indexes of the items you want to remove, and then remove them after you are done iterating.
Or you can copy all the ones you want to keep into a new list as you iterate, and then discard the old list when done.
those options assume you have to iterate over the list to find the elements to remove -- useful in cases where the list elements are complex objects with properties you might test on.
In your particular case, you dont even need to iterate, as you can just use removeAll. Look at the API here. There are also nifty methods like retainAll that discard everything that is not in the argument. You can use remove/retain-like methods whenever the objects in the list implement equals and hashcode properly. If you cannot rely on equals/hashcode to identify equality between instances in your app, you will have to do the removal yourself....
Try this (Java 8):
list.removeIf(condition);
You could make a copy of list you want to remove element from, directly in for-each loop. For me, that is the simpliest way. Something like this:
for (String stringIter : new ArrayList<String>(myList)) {
myList.remove(itemToRemove);
}
Hope that will help you..
I think it is worth mentioning the Java 8 version
#Test
public void testListCur() {
List<String> li = new ArrayList<String>();
for (int i = 0; i < 10; i++) {
li.add("str" + i);
}
li = li.stream().filter(st -> !st.equalsIgnoreCase("str3")).collect(Collectors.toList());
System.out.println(li);
}
ArrayList has field modCount - count of collection modifications
When you invoke method iterator() creates new object Itr. It has field expectedModCount. expectedModCount field initialize by modCount value. When you invoke
li.remove("str3");
modCount increments. When do you try access to li via iterator
checks that expectedModCount == modCount
and if it is false throws ConcurrentModificationException
Hence if you get iterator and after collection modified - iterator is considered not valid and you cannot use it.
I think that best answer is from bigdev.de, but i would like to add something to it(like if the item is removed from a list, maybe you would like to log that somewhere or something):
List<String> list = new ArrayList<>();
list.removeIf(a -> {
boolean condition = a.equalsIgnoreCase("some condition");
if(condition)
logger.info("Item removed from the list: " + a);
return condition;
});
I got this problem and I think the easier way is the same with the second way that hvgotcodes gave.
Or you can copy all the ones you want to keep into a new list as you iterate, and then discard the old list when done.
#Test
public void testListCur(){
List<String> li=new ArrayList<String>();
for(int i=0;i<10;i++){
li.add("str"+i);
}
List<String> finalLi = new ArrayList<String>();
for(String st:li){
if(st.equalsIgnoreCase("str3")){
// Do nothing
} else {
finalLi.add(st);
}
}
System.out.println(finalLi);
}
I looped a different way...
public void testListCur(){
List<String> li=new ArrayList<String>();
for(int i=0;i<10;i++){
li.add("str"+i);
}
for(int i=0; i<li.size(); i++)
if(li.get(i).equalsIgnoreCase("str3"))
li.remove(i--);
System.out.println(li);
}

java - iterating a linked list

if I use a for-each loop on a linked list in java,
is it guaranteed that I will iterate on the elements in the order
in which they appear in the list?
I found 5 main ways to iterate over a Linked List in Java (including the Java 8 way):
For Loop
Enhanced For Loop
While Loop
Iterator
Collections’s stream() util (Java8)
For loop
LinkedList<String> linkedList = new LinkedList<>();
System.out.println("==> For Loop Example.");
for (int i = 0; i < linkedList.size(); i++) {
System.out.println(linkedList.get(i));
}
Enhanced for loop
for (String temp : linkedList) {
System.out.println(temp);
}
While loop
int i = 0;
while (i < linkedList.size()) {
System.out.println(linkedList.get(i));
i++;
}
Iterator
Iterator<String> iterator = linkedList.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
collection stream() util (Java 8)
linkedList.forEach((temp) -> {
System.out.println(temp);
});
One thing should be pointed out is that the running time of For Loop or While Loop is O(n square) because get(i) operation takes O(n) time(see this for details). The other 3 ways take linear time and performs better.
Linked list is guaranteed to act in sequential order.
From the documentation
An ordered collection (also known as a
sequence). The user of this interface
has precise control over where in the
list each element is inserted. The
user can access elements by their
integer index (position in the list),
and search for elements in the list.
iterator()
Returns an iterator over the elements in this list in proper sequence.
As the definition of Linkedlist says, it is a sequence and you are guaranteed to get the elements in order.
eg:
import java.util.LinkedList;
public class ForEachDemonstrater {
public static void main(String args[]) {
LinkedList<Character> pl = new LinkedList<Character>();
pl.add('j');
pl.add('a');
pl.add('v');
pl.add('a');
for (char s : pl)
System.out.print(s+"->");
}
}
Linked list does guarantee sequential order.
Don't use linkedList.get(i), especially inside a sequential loop since it defeats the purpose of having a linked list and will be inefficient code.
Use ListIterator
ListIterator<Object> iterator = myLinkedList.listIterator();
while( iterator.hasNext()) {
System.out.println(iterator.next());
}
Each java.util.List implementation is required to preserve the order so either you are using ArrayList, LinkedList, Vector, etc. each of them are ordered collections and each of them preserve the order of insertion (see http://download.oracle.com/javase/1.4.2/docs/api/java/util/List.html)
Adding my inputs for future visitors.
First things first: as per $jls-14.14.2, for-each internally use Iterator.
Now, when you iterate over LinkedList using a for-each or an iterator then the looping is always sequential.
But this is prone to thread safety issues. So, two things can happen:
If you use a non-threadsafe List implementation then you will run into ConcurrentModificationException
You can use a threadsafe List implementation like CopyOnWriteArrayList. And if you must use a LinkedList only then use Collections.synchronizedList() to convert your non-threadsafe LL into a threadsafe LL, but again you need to watch out for using iterator in a threadsafe manner.

Categories

Resources