Почему я не могу использовать foreach на перечислении Java?


почему я не могу сделать:

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

6 ответов:

, потому что Enumeration<T> не распространяется Iterable<T>. Вот это пример создания итерационных перечислений.

почему это интересный вопрос. Это не совсем ваш вопрос, но он проливает некоторый свет на это. Из JAVA Collections API Design FAQ:

почему итератор не расширяет перечисление?

мы просматриваем имена методов для Перечисление как несчастный. Они очень долго, и очень часто используется. Учитывая, что мы добавляли метод и создавая совершенно новую структуру, мы считает, что было бы глупо не воспользуйтесь возможностью улучшите имена. Конечно, мы могли бы поддержите новые и старые имена внутри Итератор, но это не кажется стоящий.

это в основном говорит мне о том, что Sun хочет дистанцироваться от перечисления, что очень рано Java с довольно многословным синтаксис.

используя служебный класс Collections, перечисление можно сделать итерационным, например:

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

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

я решил эту проблему с двумя очень простыми классами, один для Enumeration и Iterator. Оболочка перечисления выглядит следующим образом:

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"); }
}

который может быть использован либо со статическим методом утилиты (который является моим предпочтением):

/**
 * 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)) {
    ...
    }

или путем создания экземпляра класса:

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

новый стиль для цикла ("foreach") работает с массивами и вещами, которые реализуют Iterable интерфейс.

это также более аналогично Iterator чем Iterable, Так что это не имеет смысла для Enumeration работать с foreach если Iterator тоже (и это не). Enumeration также не рекомендуется в пользу Iterator.

Enumeration не выполнять Iterable и как таковой не может быть использован непосредственно в цикле foreach. Однако с помощью Apache Commons Collections можно перебирать перечисление с помощью:

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

вы также можете использовать сокращенный синтаксис с Collections.list() но это менее эффективно (две итерации по элементам и больше памяти) :

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

потому что перечисление (и большинство классов, производных от этого интерфейса) не реализует Iterable.

вы можете попытаться написать свой собственный класс-оболочку.