Home  >  Article  >  Java  >  Detailed explanation of for-each loop and iteration in JAVA

Detailed explanation of for-each loop and iteration in JAVA

高洛峰
高洛峰Original
2017-01-21 16:43:061317browse

When learning collection in java, I noticed that the root interface Collection of the collection level implements the Iterable8742468051c85b06f0a0af9e3e506b5c interface (located in the java.lang package). Implementing this interface allows the object to become the target of the "foreach" statement, and this The only method in the interface implemented is to return an iterator that iterates over a set of elements of type T.

1. IteratorIterator

Interface: Iterator8742468051c85b06f0a0af9e3e506b5c

public interface Iterator<E>{
  boolean hasNext();
 E next();
 void remove();
 }

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

Of particular note 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 Iterator8742468051c85b06f0a0af9e3e506b5c 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 as 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 when running, because we did not use the iterator during the iterator operation remove() method to remove elements, but use the ArrayList's remove() method to change 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 Iterator8742468051c85b06f0a0af9e3e506b5c

Since 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 over 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 foreach loop must implement the Iterable8742468051c85b06f0a0af9e3e506b5c interface

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 because the CustomCollection class in the code does not implement the Iterable8742468051c85b06f0a0af9e3e506b5c interface. 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

It can be confirmed again from the above example that the foreach loop only applies to objects that implement the Iterable8742468051c85b06f0a0af9e3e506b5c 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 example at the beginning 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 the Iterator is used inside the for-each loop to traverse the Collection. It also calls Iterator.next(), which checks (the element) changes and throws ConcurrentModificationException.

Summary:

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

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

The above is the entire content of this article. I hope it will be helpful to everyone's study. I also hope that everyone will support the PHP Chinese website.

For more detailed articles related to for-each loop and iteration in JAVA, please pay attention to the PHP Chinese website!


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
Previous article:Rules for Java data typesNext article:Rules for Java data types