>  기사  >  Java  >  JAVA의 for-each 루프 및 반복에 대한 자세한 설명

JAVA의 for-each 루프 및 반복에 대한 자세한 설명

高洛峰
高洛峰원래의
2017-01-21 16:43:061373검색

Java에서 컬렉션을 학습할 때 컬렉션 수준의 루트 인터페이스인 Collection이 Iterable8742468051c85b06f0a0af9e3e506b5c 인터페이스(java.lang 패키지에 있음)를 구현한다는 것을 알았습니다. foreach" 문 및 이 구현된 인터페이스의 유일한 메서드는 T 유형의 요소 집합을 반복하는 반복기를 반환하는 것입니다.

1. Iterator Iterator

인터페이스: Iterator8742468051c85b06f0a0af9e3e506b5c

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

Iterator 인터페이스 API를 보면 다음과 같은 것을 알 수 있습니다. 컬렉션입니다. 반복할 반복자입니다. 반복자를 사용하면 호출자는 잘 정의된 의미 체계를 사용하여 반복 중에 반복자가 가리키는 컬렉션에서 요소를 제거할 수 있습니다.

특히 주목할 점은 이 반복자의 제거() 메서드를 사용하는 것입니다. 즉, 반복자가 가리키는 컬렉션에서 반복자가 반환한 마지막 요소(선택적 작업)를 제거하는 것입니다. 이 메서드는 next 호출당 한 번만 호출할 수 있습니다. 반복자가 가리키는 컬렉션이 이 메서드(제거 메서드)를 호출하는 것 이외의 반복 중에 수정되는 경우 반복자의 동작은 정의되지 않습니다. 인터페이스 디자이너는 Iterator8742468051c85b06f0a0af9e3e506b5c 인터페이스를 설계할 때 반복 중에 반복자가 가리키는 컬렉션을 수정하기 위해 반복자가 아닌 제거() 메서드를 호출하면 불확실한 결과가 발생할 수 있음을 지적했습니다. 구체적인 결과는 반복자의 구체적인 구현에 따라 달라집니다. 그러한 불확실한 결과가 발생할 수 있는 가능한 상황에 대응하여 ArrayList를 학습할 때 그 중 하나에 직면했습니다. 반복자가 ConcurrentModificationException 예외를 던졌습니다. 구체적인 예외는 다음 코드에 나와 있습니다.

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
    }
  }
 
}

이 코드는 작업 중에 반복자를 사용하지 않기 때문에 실행 시 ConcurrentModificationException을 발생시킵니다. 요소를 제거하려면 반복자 제거() 메서드를 사용하고, 반복자가 가리키는 컬렉션을 변경하려면 ArrayList의 제거() 메서드를 사용합니다. 이는 반복자의 설계 원칙을 위반하므로 예외가 발생합니다.

보고된 예외는 다음과 같습니다.

java.util.ArrayList$Itr.checkForComodification의 스레드 "main" java.util.ConcurrentModificationException
예외( ArrayList.java:859)
at java.util.ArrayList$Itr.next(ArrayList.java:831)
at Text.ItaratorTest.main(ItaratorTest.java:17)

2. for-each 루프 및 반복자 Iterator

Java5부터 Java에는 컬렉션과 배열을 반복하는 데 사용할 수 있는 for-each 루프가 있습니다. Foreach 루프를 사용하면 기존 for 루프에서 인덱스를 유지하지 않거나 iterator/ListIterator(ArrayList의 반복기 구현)를 사용할 때 while 루프에서 hasNext() 메서드를 호출하지 않고 컬렉션을 반복할 수 있습니다. for-each 루프는 컬렉션이나 배열을 순회하는 프로세스를 단순화합니다. 그러나 foreach 루프를 사용할 때 주의해야 할 두 가지 사항이 있습니다.

foreach 루프를 사용하는 객체는 Iterable8742468051c85b06f0a0af9e3e506b5c 인터페이스를 구현해야 합니다.

다음 예를 참조하세요.

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);
    }
 
  }
}

코드의 CustomCollection 클래스가 Iterable8742468051c85b06f0a0af9e3e506b5c 인터페이스를 구현하지 않기 때문에 위 코드는 컴파일되지 않습니다.

스레드 "main"의 예외입니다. java.lang .Error: 해결되지 않은 컴파일 문제:
Text.ForeachTest1.main(ForeachTest1.java:15)

에서 java.lang.Iterable


의 배열이나 인스턴스에 대해서만 반복할 수 있습니다.

실제로 오류를 찾기 위해 컴파일할 때까지 기다릴 필요가 없습니다. Eclipse는 다음 코드를 작성한 후 foreach 루프에 오류를 표시합니다. 배열 또는 java.lang의 인스턴스에 대해서만 반복할 수 있습니다. Iterable

위의 예에서 다시 확인할 수 있는 것은 foreach 루프가 Iterable8742468051c85b06f0a0af9e3e506b5c 인터페이스를 구현하는 객체에만 적용된다는 것입니다. 내장된 모든 Collection 클래스는 java.util.Collection 인터페이스를 구현하고 Iterable을 상속받았으므로 위의 문제를 해결하려면 간단히 CustomCollection이 Collection 인터페이스를 구현하도록 하거나 AbstractCollection을 상속하도록 선택할 수 있습니다. 해결 방법은 다음과 같습니다.

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. foreach 루프의 내부 구현도 Iterator에 의존합니다.

foreach 루프가 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");
 
    // 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 스레드 "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:859)
at java.util.ArrayList$Itr.next(ArrayList.java:831)
Text.ItaratorTest.main(ItaratorTest.java:22)

이 예외는 Iterator가 컬렉션을 순회하기 위해 for-each 루프 내에서 사용된다는 것을 보여줍니다. ()는 (요소의) 변경 사항을 확인하고 ConcurrentModificationException을 발생시킵니다.

요약:

컬렉션을 순회할 때 순회 중에 컬렉션을 수정하려면 Iterator/listIterator를 통해 수정해야 합니다. 그렇지 않으면 "결정되지 않은 결과"가 발생할 수 있습니다.

foreach 루프는 반복자를 통해 구현됩니다. foreach 루프를 사용하는 객체는 Iterable 인터페이스를 구현해야 합니다

위 내용은 이 글의 전체 내용입니다. 모든 분들의 학습에 도움이 되기를 바랍니다. 또한 모든 분들이 PHP 중국어 웹사이트를 지지해 주시길 바랍니다.

JAVA의 for-each 루프 및 반복과 관련된 자세한 기사는 PHP 중국어 웹사이트를 참고하세요!


성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.