Frage

Warum wird die Iterator Schnittstelle nicht Iterable verlängern?

Die iterator() Methode könnte einfach zurückgeben this.

Ist es absichtlich oder nur ein Versehen von Java-Designer?

Es wäre zweckmäßig, eine für-jede Schleife mit Iteratoren wie diese verwenden zu können:

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

wo listSomeObjects() einen Iterator zurück.

War es hilfreich?

Lösung

Da im Allgemeinen ein Iterator auf eine einzige Instanz in einer Sammlung zeigt. Iterable bedeutet, dass man einen Iterator von einem Objekt erhalten kann seine Elemente zu durchqueren über -. Und es gibt keine Notwendigkeit, über eine einzelne Instanz zu durchlaufen, das ist das, was ein Iterator stellt

Andere Tipps

Ein Iterator ist Stateful. Die Idee ist, dass, wenn Sie Iterable.iterator() zweimal anrufen werden Sie bekommen unabhängig Iteratoren - für die meisten Iterables, sowieso. Der klar wäre nicht der Fall in Ihrem Szenario sein.

Zum Beispiel kann ich in der Regel schreiben:

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

Das sollte die Sammlung druckt zweimal - aber mit System würde die zweite Schleife immer sofort beenden

.

Für meine $ 0,02, bin ich völlig einverstanden, dass Iterator sollte Iterable nicht umsetzen, aber ich denke, die erweiterte for-Schleife entweder akzeptieren sollte. Ich denke, die ganze „Iteratoren machen iterable“ Argument kommt um in der Sprache eines Defekts als Arbeit.

Der ganze Grund für die Einführung der for-Schleife verbessert war, dass es „beseitigt die Plackerei und Fehleranfälligkeit von Iteratoren und Indexvariablen, wenn sie über Sammlungen und Arrays iterieren“ [ 1 ].

Collection<Item> items...

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

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

Warum dann dieses gleiche Argument hält nicht für Iteratoren?

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

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

In beiden Fällen werden die Anrufe zu hasNext () und next () entfernt worden ist, und es gibt keinen Hinweis auf die Iterator in der inneren Schleife. Ja, ich verstehe, dass Iterables wiederverwendet werden kann mehrere Iteratoren zu schaffen, sondern dass alle außerhalb der for-Schleife geschieht: in der Schleife gibt immer nur ein nach vorn über den Elementen zu einem Zeitpunkt Progression eines Element ist durch den Iterator zurückgegeben <. / p>

Auch dies erlaubt würde auch macht es einfach, die für Aufzählungen for-Schleife zu verwenden, die, wie an anderer Stelle darauf hingewiesen wurde, analog zu Iteratoren nicht Iterables.

Also nicht machen Iterator Iterable implementieren, aber die for-Schleife aktualisieren, entweder zu akzeptieren.

Cheers,

Wie bereits von anderen erwähnt, Iterator und Iterable sind zwei verschiedene Dinge.

Auch Iterator Implementierungen datiert für Schleifen verbessert.

Es ist auch trivial diese Einschränkung mit einem einfachen Adapter Verfahren zu überwinden, die so aussieht, als mit statischer Methode Importen verwendet:

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

Beispielimplementierung:

  /**
   * 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();
  }

In Java 8 eine Iterator zu einem Iterable Anpassung wird einfacher:

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

Wie bereits gesagt wurde, kann ein Iterable mehrmals aufgerufen werden, bei jedem Aufruf einen neuen Iterator zurückkehrt; ein Iterator wird nur einmal verwendet. So sind sie verwandt, aber unterschiedlichen Zwecken dienen. Frustrierend, aber die „compact für“ Methode funktioniert nur mit einem iterable.

Was werde ich beschreiben unten ist eine Möglichkeit, das Beste aus beiden Welten haben -. Ein Iterable Rückkehr (für schönere Syntax), auch wenn die zugrunde liegende Sequenz von Daten ist einmalig

Der Trick ist eine anonyme Implementierung des Iterable zurückzukehren, die die Arbeit tatsächlich auslöst. Anstatt also die Arbeit zu tun, die eine einmalige Sequenz erzeugt und dann einen Iterator über die Rückkehr, kehren Sie eine Iterable, die jedes Mal zugegriffen wird, die Arbeit nachvollzieht. Das mag verschwenderisch, aber oft werden Sie nur die Iterable rufen einmal sowieso, und selbst wenn man es nennen mehrere Male, es hat immer noch vernünftige Semantik (im Gegensatz zu einem einfachen Wrapper, der einen Iterator „aussehen“ ein Iterable macht, diese won‘ t fehlschlagen, wenn zweimal verwendet).

Zum Beispiel, sagen, ich habe eine DAO, die eine Reihe von Objekten aus einer Datenbank bereitstellt, und ich mag den Zugriff auf das über einen Iterator zur Verfügung zu stellen (z. B. zu vermeiden, alle Objekte im Speicher zu schaffen, wenn sie nicht benötigt werden). Jetzt konnte ich nur einen Iterator zurück, aber das macht in einer Schleife hässlich den zurückgegebenen Wert verwenden. Anstatt also ich wickeln alles in einem 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();
            }
        };
    }
}

Dies kann dann in Code wie folgt verwendet werden:

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

, die mich für Schleife verwenden, um die kompakten kann, während immer noch inkrementellen Speicherverbrauch zu halten.

Dieser Ansatz ist „faul“ - die Arbeit getan ist nicht, wenn die Iterable angefordert wird, sondern erst später, wenn der Inhalt iteriert werden - und Sie müssen die Folgen davon zu beachten. Im Beispiel mit einem DAO, die über die Ergebnisse in dem Datenbank-Transaktionsmittel läuft.

So gibt es verschiedene Einschränkungen, aber das kann noch ein nützliches Idiom in vielen Fällen sein.

Unglaublich, hat niemand sonst diese Antwort noch gegeben. Hier ist, wie man „leicht“ durchläuft eine Iterator durch die neue Java 8 mit Iterator.forEachRemaining() Methode:

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

Natürlich ist es eine „einfache“ Lösung, die direkt mit der foreach-Schleife arbeitet, das Einwickeln den Iterator in einem Iterable lambda:

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

Iterator ist eine Schnittstelle, die Sie über etwas zu durchlaufen können. Es ist eine Implementierung durch eine Sammlung von irgendeiner Art zu bewegen.

Iterable ist eine funktionale Schnittstelle, die zeigt, dass etwas ein zugängliches Iterator enthält.

In Java8, macht dieses Leben ziemlich einfach ... Wenn Sie eine Iterator haben, aber brauchen eine Iterable Sie können einfach tun:

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

Das funktioniert auch in der for-Schleife:

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

ich auch viele sehen dies zu tun:

public Iterator iterator() {
    return this;
}

Aber das macht es nicht richtig machen! Diese Methode wäre nicht, was Sie wollen!

Das Verfahren iterator() soll ein neues Iterator von vorne anfangen zurückzukehren. Also muss man so etwas tun:

public class IterableIterator implements Iterator, Iterable {

  //Constructor
  IterableIterator(IterableIterator iter)
  {
    this.initdata = iter.initdata;
  }
  // methods of Iterable

  public Iterator iterator() {
    return new MyClass(this.somedata);
  }

  // methods of Iterator

  public boolean hasNext() {
    // ...
  }

  public Object next() {
    // ...
  }

  public void remove() {
    // ...
  }
}

Die Frage ist: gäbe es eine Möglichkeit, eine abstrakte Klasse durchführt, dies zu machen? Deshalb sollte man, dass, um eine IterableIterator man nur noch die beiden Methoden next () und hasNext ()

implementieren

Wenn Sie auch hier auf der Suche nach einer Vermeidung des Problems kam, können Sie IteratorIterable . (Verfügbar für Java 1.6 und höher)

Beispiel für die Verwendung (Umkehren eines Vector).

import java.util.Vector;
import org.apache.commons.collections4.iterators.IteratorIterable;
import org.apache.commons.collections4.iterators.ReverseListIterator;
public class Test {
    public static void main(String ... args) {
        Vector<String> vs = new Vector<String>();
        vs.add("one");
        vs.add("two");
        for ( String s: vs ) {
            System.out.println(s);
        }
        Iterable<String> is
            = new IteratorIterable(new ReverseListIterator(vs));
        for ( String s: is ) {
            System.out.println(s);
        }
    }
}

druckt

one
two
two
one

ich mit der akzeptierten Antwort zustimmen, aber mag, dass meine eigene Erklärung hinzuzufügen.

  • Iterator den Zustand der Verfahrgeschwindigkeit darstellt, zum Beispiel, können Sie das aktuelle Element aus einem Iterator bekommen und sich auf den nächsten verschieben.

  • Iterable stellt eine Sammlung, die durchlaufen werden könnte, kann es so viele Iteratoren zurück, wie Sie wollen, jeder hat seinen eigenen Zustand Verfahrende darstellt, ein Iterator auf das erste Element gerichtet sein kann, während ein anderer auf das Verzeichnis sein kann 3. Element.

Es wäre schön, wenn Java for-Schleife beiden Iterator und Iterable akzeptiert.

Aus Gründen der Einfachheit, Iterator und Iterable sind zwei verschiedene Konzepte, ist Iterable einfach eine Abkürzung für „Ich habe eine Iterator zurückgeben kann“. Ich denke, dass Ihr Code sollte sein:

for(Object o : someContainer) {
}

mit someContainer Instanceof SomeContainer extends Iterable<Object>

Als Nebenwirkung: Scala hat eine toIterable () -Methode in Iterator. Siehe scala implizite oder explizite Umwandlung von Iterator zu Iterable

Auf einem verwandten beachten, können Sie die IteratorIterable Adapter in Apache Commons Collections4 nützlich finden. Nur eine Instanz von einem Iterator, und Sie haben die entsprechenden iterable.

https: // commons.apache.org/proper/commons-collections/apidocs/org/apache/commons/collections4/iterators/IteratorIterable.html

ID: org.apache.commons: commons-collections4: 4.0

Iteratoren Stateful ist, sie ein „nächstes“ Element haben und sich als „erschöpft“ iteriert einmal vorbei. Um zu sehen, wo das Problem ist, den folgenden Code ausführen, wie viele Zahlen gedruckt werden?

Iterator<Integer> iterator = Arrays.asList(1,2,3).iterator();
Iterable<Integer> myIterable = ()->iterator;
for(Integer i : myIterable) System.out.print(i);
System.out.println();
for(Integer i : myIterable) System.out.print(i);

Sie können versuchen, das folgende Beispiel:

List ispresent=new ArrayList();
Iterator iterator=ispresent.iterator();
while(iterator.hasNext())
{
    System.out.println(iterator.next());
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top