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)
의 배열이나 인스턴스에 대해서만 반복할 수 있습니다.
실제로 오류를 찾기 위해 컴파일할 때까지 기다릴 필요가 없습니다. 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 중국어 웹사이트를 참고하세요!