Warum kann ich foreach nicht für Java Enumeration verwenden?


70

Warum kann ich nicht tun:

Enumeration e = ...
for (Object o : e)
  ...

4
Die Aufzählung wurde 1998 in Java 1.2 durch Iterator ersetzt und wird für die Unterstützung älterer Versionen beibehalten. Die eigentliche Frage ist, warum Sie es verwenden möchten. Möglicherweise, weil Sie eine Bibliothek verwenden, die Sie dazu zwingt?
Peter Lawrey

2
@ Peter - ja, eine externe Bibliothek ist die Antwort.
Ripper234

Antworten:


63

Weil Enumeration<T>nicht verlängert Iterable<T>. Hier ist ein Beispiel für die Erstellung iterierbarer Aufzählungen .

Warum ist das eine interessante Frage? Dies ist nicht gerade Ihre Frage, aber sie wirft ein Licht darauf. Aus den häufig gestellten Fragen zum Java Collections API Design :

Warum erweitert Iterator die Aufzählung nicht?

Wir betrachten die Methodennamen für die Aufzählung als unglücklich. Sie sind sehr lang und werden sehr häufig verwendet. Angesichts der Tatsache, dass wir eine Methode hinzugefügt und ein völlig neues Framework erstellt haben, hielten wir es für dumm, die Gelegenheit zur Verbesserung der Namen nicht zu nutzen. Natürlich könnten wir die neuen und alten Namen in Iterator unterstützen, aber es scheint sich nicht zu lohnen.

Das legt mir im Grunde nahe, dass Sun sich von Enumeration distanzieren möchte, einem sehr frühen Java mit einer ziemlich ausführlichen Syntax.


21
Nächste Frage: Warum sind Aufzählungen nicht iterierbar? stackoverflow.com/questions/27240/…
Michael Myers

1
Gibt es einen semantischen Unterschied zwischen den beiden? (Ich bin nicht mit der Iterable-Klasse vertraut)? Warum nicht auch an der Aufzählung arbeiten?
Ripper234

4
Da Aufzählungen eher Iterator als Iterable ähneln (siehe die gestellte Frage zum Stapelüberlauf mmyers). Als Workaround können Sie tunfor(; e.hasMoreElements(); ) { e.getNextElement(); }
Tim

4
Aber Iteratorsauch nicht Iterable. Das kannst du nicht machen for (obj : itr). Der Grund dafür ist, dass Iterablees wirklich wiederholt iterierbar ist , während ein Iterator nur einmal iteriert werden kann.
oxbow_lakes

4
Dies erklärt nicht, warum Sun / Oracle ein Enumerationin der neuen forSyntax sowie ein Iterableund ein nicht zugelassen hat array.
mjaggard

45

Mit der Dienstprogrammklasse "Sammlungen" kann die Aufzählung wie folgt iterierbar gemacht werden:

Enumeration headerValues=request.getHeaders("mycustomheader");
List headerValuesList=Collections.list(headerValues);

for(Object headerValueObj:headerValuesList){
 ... do whatever you want to do with headerValueObj
}

4
Die Elemente werden vor Beginn der Iteration in eine neue Liste kopiert. Diese Lösung sollte bei langen Aufzählungen vermieden werden. Die Lösungen, die eine Aufzählung in einen Iterator verwandeln, haben weniger Speicheraufwand.
Emmanuel Bourg

@EmmanuelBourg, aber sie haben Nebenwirkungen, da Aufzählungen zustandsbehaftet sind.
P.Péter

1
Dies ist bei weitem die einfachste Antwort! Keine Abhängigkeiten erforderlich und klar lesbar. Vielen Dank!
Geert Schuring

7

Ich habe dieses Problem mit zwei sehr einfachen Klassen gelöst, einer für Enumerationund einer für Iterator. Der Aufzählungs-Wrapper lautet wie folgt:

static class IterableEnumeration<T>
extends Object
implements Iterable<T>, Iterator<T>
{
private final Enumeration<T>        enumeration;
private boolean                     used=false;

IterableEnumeration(final Enumeration<T> enm) {
    enumeration=enm;
    }

public Iterator<T> iterator() {
    if(used) { throw new IllegalStateException("Cannot use iterator from asIterable wrapper more than once"); }
    used=true;
    return this;
    }

public boolean hasNext() { return enumeration.hasMoreElements(); }
public T       next()    { return enumeration.nextElement();     }
public void    remove()  { throw new UnsupportedOperationException("Cannot remove elements from AsIterator wrapper around Enumeration"); }
}

Welche kann entweder mit einer statischen Dienstprogrammmethode verwendet werden (was meine Präferenz ist):

/**
 * Convert an `Enumeration<T>` to an `Iterable<T>` for a once-off use in an enhanced for loop.
 */
static public <T> Iterable<T> asIterable(final Enumeration<T> enm) {
    return new IterableEnumeration<T>(enm);
    }

...

for(String val: Util.asIterable(enm)) {
    ...
    }

oder durch Instanziieren der Klasse:

for(String val: new IterableEnumeration<String>(enm)) {
    ...
    }

3

Der New-Style-for-Loop ("foreach") funktioniert für Arrays und Dinge, die das implementieren Iterable Schnittstelle .

Es ist auch analoger Iteratorals zu Iterable, daher wäre es nicht sinnvoll Enumeration, mit foreach zu arbeiten, wenn es Iteratornicht auch so wäre (und es tut es nicht). Enumerationwird auch zugunsten von entmutigt Iterator.


1
Seien wir vorsichtig mit den Begriffen hier. Verfall bedeutet etwas sehr Spezifisches bei der Diskussion von APIs. Von der Verwendung der Aufzählung wird abgeraten, sie wird jedoch nicht veraltet.
Ykaganovich

Ykaganovich: Guter Punkt. Ich habe den Text in der Antwort korrigiert.
Laurence Gonsalves

2

Mit Java 8 und darüber hinaus ist dies möglich:

import java.util.Collections;
import java.util.Enumeration;

Enumeration e = ...;
Collections.list(e).forEach(o -> {
    ... // use item "o"
});

1

Enumerationwird nicht implementiert Iterableund kann daher nicht direkt in einer foreach-Schleife verwendet werden. Mit Apache Commons Collections ist es jedoch möglich, eine Aufzählung mit folgenden Elementen zu durchlaufen:

for (Object o : new IteratorIterable(new EnumerationIterator(e))) {
    ...
}

Sie können auch eine kürzere Syntax verwenden Collections.list(), dies ist jedoch weniger effizient (zwei Iterationen über die Elemente und mehr Speichernutzung):

for (Object o : Collections.list(e))) {
    ...
}


0

Da eine Aufzählung (und die meisten von dieser Schnittstelle abgeleiteten Klassen) Iterable nicht implementiert.

Sie können versuchen, Ihre eigene Wrapper-Klasse zu schreiben.


2
Sie sollten keinen Wrapper für Enumeration schreiben, der ihn zu einem Iterable macht, genauso wenig wie Sie einen solchen Wrapper für Iterator erstellen sollten. Iterator- und Aufzählungsobjekte sind in Bezug auf die Iteration zustandsbehaftet. Iterables sind nicht.
Laurence Gonsalves

0

Wir können die for-Schleife verwenden, um eine Aufzählung mit der zu durchlaufen .values​​()

method which returns all the elements contained in the enumeration.

Ein Beispiel :

for (USERS_ROLES userRole: USERS_ROLES .values ​​()) {
            System.out.println ("This is one user role:" + userRole.toString ());
}

Ich habe es in Java 10 gemacht

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.