2009-08-06 36 views
56

Tại sao tôi không thể làm:Tại sao tôi không thể sử dụng foreach trên Java Enumeration?

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

Điều tra đã được thay thế bằng Iterator trong Java 1.2 vào năm 1998 và được giữ lại để hỗ trợ kế thừa. Câu hỏi thực sự là lý do tại sao bạn muốn sử dụng nó. Có thể vì bạn sử dụng thư viện buộc bạn phải làm như vậy? –

+1

@Peter - vâng, thư viện bên ngoài là câu trả lời. – ripper234

Trả lời

55

Enumeration<T> không mở rộng Iterable<T>. Đây là một số example of making Iterable Enumerations.

Vì sao đó lại là một câu hỏi thú vị. Đây không phải là chính xác câu hỏi của bạn nhưng nó làm sáng tỏ nó. Từ số Java Collections API Design FAQ:

Tại sao Iterator không mở rộng liệt kê?

Chúng tôi xem tên phương thức cho Điều tra là không may. Chúng là rất dài và thường xuyên được sử dụng. Vì chúng tôi đã thêm phương thức và tạo một khung hoàn toàn mới, chúng tôi cảm thấy rằng sẽ không thành công khi tận dụng cơ hội để cải thiện tên. Tất nhiên chúng tôi có thể hỗ trợ tên mới và cũ trong Iterator, nhưng dường như không có đáng giá.

Điều đó về cơ bản gợi ý với tôi rằng Sun muốn tự tách mình khỏi Liệt kê, vốn rất sớm Java với cú pháp khá dài.

+14

Câu hỏi tiếp theo: tại sao không phải Enumerations Iterable? http://stackoverflow.com/questions/27240/why-arent-enumerations-iterable –

+1

Có sự khác biệt ngữ nghĩa giữa hai người không? (Tôi không quen thuộc với lớp Iterable)? Tại sao không có cho công việc trên Enumeration là tốt? – ripper234

+4

Bởi vì các số đếm giống như Iterator, không lặp lại được (xem các câu hỏi xếp chồng được đăng tải). Để giải quyết vấn đề này, bạn có thể làm 'for (; e.hasMoreElements();) {e.getNextElement(); } ' – Tim

3

Kiểu mới cho vòng lặp ("foreach") hoạt động trên mảng và những thứ triển khai giao diện Iterable.

Nó cũng tương tự như Iterator so với Iterable, vì vậy sẽ không có ý nghĩa đối với Enumeration để làm việc với foreach trừ khi Iterator cũng vậy (và không). Enumeration cũng không được khuyến khích ủng hộ Iterator.

+1

Hãy cẩn thận với các điều khoản tại đây. Ngừng sử dụng có nghĩa là một cái gì đó rất cụ thể khi thảo luận về API. Sử dụng liệt kê là nản lòng, nhưng nó không được chấp nhận. – ykaganovich

+0

ykaganovich: điểm tốt. Tôi đã sửa văn bản trong câu trả lời. –

0

Bởi vì một liệt kê (và hầu hết các lớp bắt nguồn từ giao diện này) không thực hiện lặp lại.

Bạn có thể thử viết lớp trình bao bọc của riêng mình.

+2

Bạn không nên viết một wrapper cho Enumeration mà biến nó thành một Iterable nhiều hơn bạn nên tạo một wrapper như vậy cho Iterator. Các đối tượng Iterator và Enumeration là stateful đối với iteration. Iterables thì không. –

6

Tôi đã giải quyết vấn đề này với hai lớp rất đơn giản, một cho Enumeration và một cho Iterator. Các wrapper liệt kê như sau:

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

Mà có thể được sử dụng với một phương pháp hữu ích tĩnh (đó là sở thích của tôi):

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

hoặc bằng instantiating lớp:

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

Sử dụng lớp tiện ích Bộ sưu tập, Danh sách có thể được lặp lại như sau:

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

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

Các yếu tố được sao chép trong một danh sách mới trước khi bắt đầu lặp lại, giải pháp này nên tránh cho các liệt kê dài. Các giải pháp chuyển một Enumeration thành Iterator có ít chi phí bộ nhớ hơn. –

+0

@EmmanuelBourg nhưng chúng có tác dụng phụ, vì liệt kê là trạng thái. –

+1

Đây là câu trả lời dễ nhất! Không cần phụ thuộc và dễ đọc. Cảm ơn! –

1

Enumeration không triển khai Iterable và vì vậy không thể sử dụng trực tiếp trong vòng lặp foreach.Tuy nhiên sử dụng Apache Commons Collections nó có thể để lặp qua một điều tra với:

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

Bạn cũng có thể sử dụng một cú pháp ngắn với Collections.list() nhưng điều này là kém hiệu quả (hai lần lặp qua các yếu tố và sử dụng bộ nhớ nhiều hơn):

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

bạn có nghĩa là [IteratorIterable] (http://commons.apache.org/proper/commons-collections/javadocs/api-release/org/apache/commons/collections4/iterators/IteratorIterable.html) không? – luckyluke

+0

@ luckyluke Vâng, cảm ơn. Tôi đã sửa lại ví dụ. –

Các vấn đề liên quan