Home >类库下载 >java类库 >for-each loop and iteration in JAVA

for-each loop and iteration in JAVA

高洛峰
高洛峰Original
2016-10-19 09:59:151867browse

1. Iterator Iterator

Interface: Iterator

public interface Iterator<E>{

 boolean hasNext();

 E next();

 void remove();
 }

Looking at the Iterator interface API, you can know that this is an iterator for iterating the collection. Iterators allow the caller to remove elements from the collection pointed to by the iterator during iteration using well-defined semantics.

Particularly noteworthy is the use of the remove() method of this iterator: remove the last element returned by the iterator (optional operation) from the collection pointed to by the iterator. This method can only be called once per call to next. If the collection pointed to by the iterator is modified during an iteration other than by calling this method (remove method), the behavior of the iterator is undefined. The interface designer pointed out when designing the Iterator interface that if the remove() method other than the iterator is called to modify the collection pointed by the iterator during iteration, it will cause uncertain consequences. The specific consequences depend on the specific implementation of the iterator. In response to the possible situations where such uncertain consequences may occur, I encountered one of them when learning ArrayList: the iterator threw a ConcurrentModificationException exception. The specific exception is shown in the following code:

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

public class ItaratorTest {

    public static void main(String[] args) {
        Collection<String> list = new ArrayList<String>();
        list.add("Android");
        list.add("IOS");
        list.add("Windows Mobile");

        Iterator<String> iterator = list.iterator();
        while (iterator.hasNext()) {
            String lang = iterator.next();
            list.remove(lang);//will throw ConcurrentModificationException
        }
    }

}

This code will throw a ConcurrentModificationException exception during runtime, because we do not use the iterator's remove() method to delete elements during the iterator's operation, but use ArrayList's remove() Method changes the collection pointed by the iterator. This violates the design principles of iterators, so an exception occurs.
The reported exception is as follows:

Exception in thread "main" java.util.ConcurrentModificationException
    at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:859)
    at java.util.ArrayList$Itr.next(ArrayList.java:831)
    at Text.ItaratorTest.main(ItaratorTest.java:17)

2. for-each loop and iterator Iterator

Starting from Java5, there is a for-each loop in Java, which can be used to loop through collections and arrays. The Foreach loop allows you to iterate through the collection without maintaining the index in a traditional for loop, or without calling the hasNext() method in the while loop when using iterator / ListIterator (an iterator implementation in ArrayList). The for-each loop simplifies the process of traversing any Collection or array. But there are two points to note when using a foreach loop.

Objects using the foreach loop must implement the Iterableinterface

Please see the following example:

import java.util.ArrayList;

public class ForeachTest1 {

    public static void main(String args[]) {
        CustomCollection<String> myCollection = new CustomCollection<String>();
        myCollection.add("Java");
        myCollection.add("Scala");
        myCollection.add("Groovy");

        // What does this code will do, print language, throw exception or
        // compile time error
        for (String language : myCollection) {
            System.out.println(language);
        }
    }

    private class CustomCollection<T> {
        private ArrayList<T> bucket;

        public CustomCollection() {
            bucket = new ArrayList();
        }

        public int size() {
            return bucket.size();
        }

        public boolean isEmpty() {
            return bucket.isEmpty();
        }

        public boolean contains(T o) {
            return bucket.contains(o);
        }

        public boolean add(T e) {
            return bucket.add(e);
        }

        public boolean remove(T o) {
            return bucket.remove(o);
        }

    }
}

The above code will not be compiled. This is because the CustomCollection class in the code does not implement the Iterableinterface. The error reported during compilation is as follows :

Exception in thread "main" java.lang.Error: Unresolved compilation problem: 
    Can only iterate over an array or an instance of java.lang.Iterable

    at Text.ForeachTest1.main(ForeachTest1.java:15)

In fact, there is no need to wait until compilation to find the error. Eclipse will display the error in the foreach loop after writing this code: Can only iterate over an array or an instance of java.lang.Iterable

What can be confirmed again from the above example is that the foreach loop only applies to objects that implement the Iterable interface. Since all built-in Collection classes implement the java.util.Collection interface and have inherited Iterable, in order to solve the above problems, you can choose to simply let CustomCollection implement the Collection interface or inherit AbstractCollection. The solution is as follows:

import java.util.AbstractCollection;
import java.util.ArrayList;
import java.util.Iterator;

public class ForeachTest {
    public static void main(String args[]) {
        CustomCollection<String> myCollection = new CustomCollection<String>();
        myCollection.add("Java");
        myCollection.add("Scala");
        myCollection.add("Groovy");
        for (String language : myCollection) {
            System.out.println(language);
        }
    }

    private static class CustomCollection<T> extends AbstractCollection<T> {
        private ArrayList<T> bucket;

        public CustomCollection() {
            bucket = new ArrayList();
        }

        public int size() {
            return bucket.size();
        }

        public boolean isEmpty() {
            return bucket.isEmpty();
        }

        public boolean contains(Object o) {
            return bucket.contains(o);
        }

        public boolean add(T e) {
            return bucket.add(e);
        }

        public boolean remove(Object o) {
            return bucket.remove(o);
        }

        @Override
        public Iterator<T> iterator() {
            // TODO Auto-generated method stub
            return bucket.iterator();
        }
    }
}

  2. The internal implementation of the foreach loop also relies on Iterator

In order to verify the fact that the foreach loop uses Iterator as the internal implementation, we still use the initial example of this article for verification:

public class ItaratorTest {

    public static void main(String[] args) {
        Collection<String> list = new ArrayList<String>();
        list.add("Android");
        list.add("IOS");
        list.add("Windows Mobile");

        // example1
        // Iterator<String> iterator = list.iterator();
        // while (iterator.hasNext()) {
        // String lang = iterator.next();
        // list.remove(lang);
        // }

        // example 2
        for (String language : list) {
            list.remove(language);
        }
    }

}

Exception reported when the program is running:

Exception in thread "main" java.util.ConcurrentModificationException
    at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:859)
    at java.util.ArrayList$Itr.next(ArrayList.java:831)
    at Text.ItaratorTest.main(ItaratorTest.java:22)

This exception shows that an Iterator is used inside the for-each loop to traverse the Collection. It also calls Iterator.next(), which checks the changes (of elements) and throws a ConcurrentModificationException.

Summary:

When traversing a collection, if you want to modify the collection during the traversal, you must do it through Iterator/listIterator, otherwise "undetermined consequences" may occur.

The foreach loop is implemented through iterator, and the object using the foreach loop must implement the Iterable interface


Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn