JAVA의 for-each 순환과 교체에 대한 상세한 설명

7486 단어 javafor-each
자바에서의collection을 배울 때collection 차원의 루트 인터페이스 Collection은 Iterable인터페이스(java.lang 패키지에 있음)를 실현했다. 이 인터페이스는 대상을'foreach'문구의 목표가 되도록 허용하고 이 인터페이스의 유일한 방법은 하나의 T 유형의 요소에 교체된 교체기를 되돌려주는 것이다.
1. 교체기 Iterator
인터페이스: Iterator

public interface Iterator<E>{
  boolean hasNext(); 
 E next(); 
 void remove();
 }
Iterator 인터페이스 API를 보면 콜렉션을 교체하는 교체기임을 알 수 있습니다.교체기는 호출자가 정의된 좋은 의미를 이용하여 교체 기간에 교체기가 가리키는 콜렉션에서 요소를 제거할 수 있도록 합니다.
특히 주의해야 할 것은 이 교체기remove () 방법의 사용입니다. 교체기가 가리키는 콜렉션에서 교체기가 되돌아오는 마지막 요소를 제거합니다.매번 넥스트를 호출할 때마다 이 방법을 한 번만 호출할 수 있습니다.만약 교체를 진행할 때 이 방법 (remove 방법) 이외의 다른 방식으로 이 교체기가 가리키는 콜렉션을 수정한다면, 교체기의 행위는 확실하지 않습니다.인터페이스 디자이너는 Iterator인터페이스를 설계할 때 교체를 진행할 때 교체기를 제외한remove () 방법을 사용하여 이 교체기가 가리키는 콜렉션을 수정하면 불확실한 결과를 초래할 수 있다고 지적했다.구체적으로 어떤 결과가 나타날지는 교체기의 구체적인 실현에 따라 결정된다.이러한 불확실한 결과가 나타날 수 있는 상황에 대해 Array List를 배울 때 그 중 하나를 만났다. 교체기가 Concurrent Modification Exception 이상을 던졌다.구체적인 이상은 다음과 같다.

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 이상을 던집니다. 왜냐하면 우리는 교체기가 실행되는 동안iterator의remove () 방법으로 요소를 삭제하지 않고 ArrayList의remove () 방법으로 교체기가 가리키는 collection을 바꾸었기 때문입니다.이것은 교체기의 설계 원칙을 위반하여 이상이 발생했다.
보고된 예외 사항은 다음과 같습니다.
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 순환과 교체기 Iterator
Java5부터 Java에 for-each 순환이 있어서 콜렉션과array를 순환할 수 있습니다.Foreach 순환은 전통적인 for 순환의 인덱스를 유지하지 않거나iterator/ListIterator (Array List의 일종의 교체기 구현) 를 사용할 때while 순환의hasNext () 방법을 사용하지 않고collection을 반복할 수 있도록 합니다.for-each 순환은 모든 컬렉션이나array의 반복 과정을 간소화합니다.하지만foreach 순환을 사용하는 것도 두 가지 주의해야 한다.
foreach 순환을 사용하는 대상은 Iterable 인터페이스를 구현해야 합니다
다음 예제를 참조하십시오.

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 클래스가 Iterable 인터페이스를 실현하지 못했기 때문입니다. 컴파일 기간의 오류는 다음과 같습니다.
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)
사실상, 컴파일할 때 오류를 발견할 필요가 없습니다. eclipse는 이 코드를 다 쓴 후foreach 순환에 오류를 표시합니다. Can onlyiterate over anarray or an instance of java.lang.Iterable
상기 예시에서 다시 한 번 확인할 수 있는 것은foreach 순환은 Iterable 인터페이스를 실현하는 대상에만 적용된다는 것이다.모든 내장 컬렉션 클래스가java를 실현했기 때문입니다.util.Collection 인터페이스는 이미 Iterable을 계승했기 때문에 상술한 문제를 해결하기 위해 간단하게 Custom Collection이 Collection 인터페이스를 실현하거나 Abstract Collection을 계승할 수 있습니다.해결 방법은 다음과 같습니다.

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 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)
이 이상은 for-each 순환 내부에서 Iterator를 사용하여 컬렉션을 훑어보았고, Iterator를 호출했음을 설명합니다.next (), 이것은 (요소의) 변화를 검사하고 ConcurrentModificationException을 던집니다.
요약:
  • 컬렉션을 반복할 때 컬렉션을 수정하려면 Iterator/listIterator를 통해 이루어져야 합니다. 그렇지 않으면'불확실한 결과'가 발생할 수 있습니다.
  • foreach 순환은iterator를 통해 이루어지고, foreach 순환을 사용하는 대상은 반드시 Iterable 인터페이스를 실현해야 한다.
  • 이상은 본문의 전체 내용입니다. 여러분의 학습에 도움이 되고 저희를 많이 응원해 주십시오.

    좋은 웹페이지 즐겨찾기