왜 Java의 Iterator가 Iterable이 아닌가? 의도적이거나 단순한 감독입니까? 다음과 같이

Iterator인터페이스가 확장되지 Iterable않습니까?

iterator()메소드는 단순히을 리턴 할 수 this있습니다.

Java 디자이너의 의도적이거나 단순한 감독입니까?

다음과 같이 반복자와 함께 for-each 루프를 사용하는 것이 편리합니다.

for(Object o : someContainer.listSomeObjects()) {
    ....
}

여기서 listSomeObjects()반복자를 반환합니다.



답변

반복자는 일반적으로 컬렉션의 단일 인스턴스를 가리 킵니다. Iterable은 객체에서 요소를 가로 지르기 위해 객체에서 반복자를 얻을 수 있음을 의미하며 단일 인스턴스를 반복 할 필요가 없습니다. 이터레이터가 나타내는 것입니다.


답변

반복자는 상태 저장입니다. 아이디어는 Iterable.iterator()두 번 호출 하면 독립적 인 반복자를 얻을 수 있다는 것 입니다. 귀하의 시나리오에서는 그렇지 않습니다.

예를 들어, 나는 보통 다음과 같이 쓸 수 있습니다.

public void iterateOver(Iterable<String> strings)
{
    for (String x : strings)
    {
         System.out.println(x);
    }
    for (String x : strings)
    {
         System.out.println(x);
    }
}

컬렉션을 두 번 인쇄해야하지만 스키마를 사용하면 두 번째 루프가 항상 즉시 종료됩니다.


답변

내 $ 0.02의 경우, Iterator가 Iterable을 구현해서는 안된다는 것에 전적으로 동의하지만, 향상된 for 루프는 어느 쪽이든 받아 들여야한다고 생각합니다. 나는 “반복자를 반복 가능하게 만든다”는 주장이 언어의 결함에 대한 해결책으로 나온다고 생각한다.

향상된 for 루프가 도입 된 이유는 “컬렉션과 배열을 반복 할 때 반복자와 인덱스 변수의 혼란과 오류가 발생하지 않기 때문입니다”[ 1 ].

Collection<Item> items...

for (Iterator<Item> iter = items.iterator(); iter.hasNext(); ) {
    Item item = iter.next();
    ...
}

for (Item item : items) {
    ...
}

그렇다면 왜이 같은 주장이 반복자에게 적용되지 않습니까?

Iterator<Iter> iter...
..
while (iter.hasNext()) {
    Item item = iter.next();
    ...
}

for (Item item : iter) {
    ...
}

두 경우 모두 hasNext () 및 next ()에 대한 호출이 제거되었으며 내부 루프의 반복자에 대한 참조가 없습니다. 예, Iterables를 사용하여 여러 반복기를 만들 수 있지만 모든 루프 외부에서 발생한다는 것을 알고 있습니다.

또한 이것을 허용하면 다른 곳에서 지적했듯이 반복문이 아닌 반복자와 유사한 열거 형 for 루프를 쉽게 사용할 수 있습니다.

따라서 Iterator를 Iterable로 구현하지 말고 for 루프를 업데이트하여 둘 중 하나를 수락하십시오.

건배,


답변

마찬가지로 다른 사람에 의해 지적, Iterator그리고 Iterable다른 두 가지입니다.

또한 Iterator구현은 향상된 for 루프보다 우선합니다.

정적 메소드 가져 오기와 함께 사용할 때 다음과 같은 간단한 어댑터 메소드로이 제한 사항을 극복하는 것은 사소한 일입니다.

for (String line : in(lines)) {
  System.out.println(line);
}

샘플 구현 :

  /**
   * Adapts an {@link Iterator} to an {@link Iterable} for use in enhanced for
   * loops. If {@link Iterable#iterator()} is invoked more than once, an
   * {@link IllegalStateException} is thrown.
   */
  public static <T> Iterable<T> in(final Iterator<T> iterator) {
    assert iterator != null;
    class SingleUseIterable implements Iterable<T> {
      private boolean used = false;

      @Override
      public Iterator<T> iterator() {
        if (used) {
          throw new IllegalStateException("SingleUseIterable already invoked");
        }
        used = true;
        return iterator;
      }
    }
    return new SingleUseIterable();
  }

Java 8에서는 an Iterator에 적응하는 것이 Iterable더 간단합니다.

for (String s : (Iterable<String>) () -> iterator) {

답변

다른 사람들이 말했듯이, Iterable은 여러 번 호출 될 수 있으며 각 호출마다 새로운 Iterator를 반환합니다. 반복자는 한 번만 사용됩니다. 그래서 그들은 관련되어 있지만 다른 목적으로 사용됩니다. 그러나 “compact for”방법은 반복적으로 만 작동합니다.

아래에서 설명하는 것은 두 데이터를 모두 활용하는 한 가지 방법입니다. 기본 데이터 시퀀스가 ​​일 회일 때도 (더 나은 구문을 위해) Iterable을 반환합니다.

트릭은 실제로 작업을 트리거하는 Iterable의 익명 구현을 리턴하는 것입니다. 따라서 일회성 시퀀스를 생성 한 다음 반복자를 반환하는 작업을 수행하는 대신 액세스 할 때마다 작업을 다시 실행하는 Iterable을 반환합니다. 그것은 낭비 적 인 것처럼 보일 수도 있지만, 어쨌든 한 번만 Iterable을 호출 할 것입니다. 여러 번 호출하더라도 여전히 합리적인 의미를 갖습니다 (Iterator를 “Iterable처럼 보이게하는 간단한 래퍼와 달리” 두 번 사용하면 실패합니다).

예를 들어, 데이터베이스에서 일련의 객체를 제공하는 DAO가 있고 반복자를 통해 액세스 할 수 있도록하려고합니다 (예 : 필요하지 않은 경우 메모리에 모든 객체를 생성하지 않기 위해). 이제 반복자를 반환 할 수는 있지만 반환 된 값을 루프에서 못 생겼습니다. 따라서 대신 모든 것을 Anon Iterable에 래핑합니다.

class MetricDao {
    ...
    /**
     * @return All known metrics.
     */
    public final Iterable<Metric> loadAll() {
        return new Iterable<Metric>() {
            @Override
            public Iterator<Metric> iterator() {
                return sessionFactory.getCurrentSession()
                        .createQuery("from Metric as metric")
                        .iterate();
            }
        };
    }
}

그러면 다음과 같은 코드에서 사용될 수 있습니다.

class DaoUser {
    private MetricDao dao;
    for (Metric existing : dao.loadAll()) {
        // do stuff here...
    }
}

그래도 증분 메모리 사용을 유지하면서 컴팩트 한 for 루프를 사용할 수 있습니다.

이 접근 방식은 “게으른”것입니다. Iterable이 요청 될 때 작업이 완료되지 않고 나중에 내용이 반복 될 때만 수행되며 그 결과를 알고 있어야합니다. DAO가있는 예에서 이는 데이터베이스 트랜잭션 내에서 결과를 반복한다는 의미입니다.

따라서 여러 가지 경고가 있지만 여전히 많은 경우에 유용한 관용구가 될 수 있습니다.


답변

놀랍게도 아직 아무도이 대답을하지 않았습니다. Iterator새로운 Java 8 Iterator.forEachRemaining()메소드를 사용하여 “간편하게”반복하는 방법은 다음과 같습니다 .

Iterator<String> it = ...
it.forEachRemaining(System.out::println);

물론 foreach 루프와 직접 작동 Iterator하여 Iterable람다로 감싸는 “더 간단한”솔루션이 있습니다 .

for (String s : (Iterable<String>) () -> it)
    System.out.println(s);

답변

Iterator무언가를 반복 할 수있는 인터페이스입니다. 일종의 컬렉션을 통해 이동하는 구현입니다.

Iterable 액세스 가능한 반복자가 포함 된 것을 나타내는 기능 인터페이스입니다.

Java8에서 이것은 인생을 아주 쉽게 만듭니다 … 당신이 Iterator있지만 필요하다면 Iterable간단하게 할 수 있습니다 :

Iterator<T> someIterator;
Iterable<T> = ()->someIterator;

for 루프에서도 작동합니다.

for (T item : ()->someIterator){
    //doSomething with item
}