2009-08-06 109 views
56

爲什麼我不能做:爲什麼我不能在Java枚舉中使用foreach?

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

枚舉在1998年被Java 1.2中的迭代器所取代,並被保留用於傳統支持。真正的問題是你爲什麼要使用它。可能是因爲你使用強迫你這樣做的圖書館? – 2010-08-27 21:57:10

+1

@彼得 - 是的,外部圖書館是答案。 – ripper234 2010-08-29 20:19:41

回答

55

因爲Enumeration<T>沒有延伸Iterable<T>。這是一個example of making Iterable Enumerations

至於爲什麼這是一個有趣的問題。這不完全是你的問題,但它可以揭示一些問題。從Java Collections API Design FAQ

爲什麼Iterator不能擴展枚舉?

我們查看 枚舉的方法名稱不幸。它們非常長,並且非常頻繁地使用,它們是 。 鑑於我們正在添加一個方法並創建了一個全新的框架,我們 認爲這將是愚蠢的,不要 趁機改名爲 。當然我們可以在 支持新舊名稱的迭代器,但似乎並不值得。

這基本上告訴我,Sun想要遠離Enumeration,這是非常早期的Java語言,具有相當冗長的語法。

+14

下一個問題:爲什麼枚舉不能迭代? http://stackoverflow.com/questions/27240/why-arent-enumerations-iterable – 2009-08-06 16:37:10

+1

這兩者之間有語義上的區別嗎? (我不熟悉Iterable類)?爲什麼不能在Enumeration上工作呢? – ripper234 2009-08-06 16:37:22

+4

由於枚舉更類似於迭代器,而不是Iterable(請參閱發佈的stackoverflow問題)。作爲解決方法,您可以執行'for(; e.hasMoreElements();){e.getNextElement(); }' – Tim 2009-08-06 16:40:24

3

新樣式for循環(「foreach」)適用於數組,以及實現Iterable接口的事物。

它也更類似於IteratorIterable,所以它是沒有意義的Enumeration用foreach工作,除非Iterator沒有太(與事實並非如此)。 Enumeration也不鼓勵Iterator

+1

讓我們在這裏小心一點。棄用意味着在討論API時非常具體。枚舉的使用是不鼓勵的,但它不被棄用。 – ykaganovich 2009-08-06 17:25:45

+0

ykaganovich:好點。我已經更正了答案中的文字。 – 2009-08-06 19:38:40

0

因爲Enumeration(和大多數從這個接口派生的類)沒有實現Iterable。

您可以嘗試編寫自己的包裝類。

+2

你不應該爲Enumeration編寫一個包裝器,將它變成一個Iterable,而不是你應該爲Iterator創建這樣一個包裝器。迭代器和枚舉對象在迭代方面是有狀態的。可信物不是。 – 2009-08-06 19:40:31

6

我已經用兩個非常簡單的類來解決這個問題,一個用於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)) { 
    ... 
    } 
31

使用集合實用程序類,枚舉可以進行迭代,如:

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

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

在開始迭代之前將元素複製到新列表中,對於長枚舉應該避免使用此解決方案。將Enumeration轉換爲Iterator的解決方案具有較少的內存開銷。 – 2014-12-18 09:21:19

+0

@EmmanuelBourg但他們有副作用,因爲枚舉是有狀態的。 – 2016-03-17 10:39:51

+1

這是迄今爲止最簡單的答案!不需要依賴關係,並且清晰可讀。謝謝! – 2016-03-30 12:26:44

1

Enumeration沒有實現Iterable,因此不能直接在foreach循環中使用。然而,使用Apache Commons Collections有可能重複的進行枚舉:

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

您也可以使用更短的語法與Collections.list()但這是效率較低(兩次迭代通過元素和使用更多內存):

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

你的意思是[IteratorIterable](http://commons.apache.org/proper/commons-collections/javadocs/api-release/org/apache/commons/collections4/iterators/IteratorIterable.html)? – luckyluke 2016-11-04 21:13:00

+0

@luckyluke是的,謝謝。我修正了這個例子。 – 2016-11-04 22:51:56

相關問題