2014-04-24 17 views
58

Có thể lặp lại một Enumeration bằng cách sử dụng Biểu thức Lambda không? Đại diện Lambda của đoạn mã sau đây là gì:Lặp lại một liệt kê trong Java 8

Enumeration<NetworkInterface> nets = NetworkInterface.getNetworkInterfaces(); 

while (nets.hasMoreElements()) { 
    NetworkInterface networkInterface = nets.nextElement(); 

} 

Tôi không tìm thấy bất kỳ luồng nào trong đó.

+7

Các số được thay thế bằng bộ lặp trong Java 1.2 vào năm 1998. Thật không may bạn vẫn phải sử dụng nó. : | –

+1

Bạn có thể điều chỉnh Enumeration to Iterator: http://stackoverflow.com/questions/5007082/treat-enumerationt-as-iteratort – marcinj

+5

@PeterLawrey Iterator xuất hiện, nhưng vẫn còn các API lõi sử dụng Enumeration. Generics xuất hiện, nhưng vẫn có các API lõi sử dụng các kiểu trống hoặc trả về Object. Lambdas xuất hiện, nhưng Swing vẫn đầy giao diện đa phương thức, vì vậy chúng tôi không thể sử dụng chúng. Nó không thực sự làm tôi ngạc nhiên nữa khi tôi tìm thấy các API mà Java quên hiện đại hóa; nó chỉ làm tôi buồn. – Trejkaz

Trả lời

26

Trong trường hợp bạn không thích thực tế rằng Collections.list(Enumeration) sao chép toàn bộ nội dung vào một (tạm thời) danh sách trước khi lặp đi lặp lại bắt đầu, bạn có thể giúp mình ra với một phương pháp hữu ích đơn giản:

public static <T> void forEachRemaining(Enumeration<T> e, Consumer<? super T> c) { 
    while(e.hasMoreElements()) c.accept(e.nextElement()); 
} 

Sau đó, bạn chỉ có thể làm forEachRemaining(enumeration, lambda-expression); (tâm tính năng import static) ...

78

(Câu trả lời này cho thấy một trong nhiều tùy chọn. Chỉ vì có dấu chấp nhận, không có nghĩa là tốt nhất. Tôi đề nghị đọc câu trả lời khác và chọn câu trả lời tùy theo tình huống của bạn. cho Java 8 tôi tìm Holger's answer đẹp nhất bởi vì nó cũng rất đơn giản nhưng không cần thêm lặp -. mà xảy ra trong dung dịch của tôi nhưng đối với Java 9 giải pháp truy cập Tagir Valeev answer)


bạn có thể sao chép các yếu tố từ Enumeration của bạn để ArrayList với Collections.list và sau đó sử dụng nó như

Collections.list(yourEnumeration).forEach(yourAction); 
+12

Việc nắm bắt là bây giờ bạn phải lưu trữ tất cả các yếu tố trong một danh sách. Mà nếu nó nhỏ, có lẽ là tốt. Nhưng nó đáng nói đến, bởi vì đôi khi nó sẽ quá lớn để phù hợp với trí nhớ. – Trejkaz

+0

Làm thế nào về java.util.stream.Stream # of (yourEnumeration.values ​​()). ForEach()? – Filip

+2

@Filip Nhận xét của bạn về ['Enum'] (https://docs.oracle.com/javase/8/docs/api/java/lang/Enum.html) nhưng câu hỏi là về [' Enumeration'] (https : //docs.oracle.com/javase/8/docs/api/java/util/Enumeration.html). – Pshemo

47

Nếu có rất nhiều Enumerations trong mã của bạn, tôi khuyên bạn nên tạo một trợ giúp tĩnh phương pháp er, có thể chuyển đổi một Số đếm thành Luồng. Phương pháp tĩnh có thể trông như sau:

public static <T> Stream<T> enumerationAsStream(Enumeration<T> e) { 
    return StreamSupport.stream(
     Spliterators.spliteratorUnknownSize(
      new Iterator<T>() { 
       public T next() { 
        return e.nextElement(); 
       } 
       public boolean hasNext() { 
        return e.hasMoreElements(); 
       } 
      }, 
      Spliterator.ORDERED), false); 
} 

Sử dụng phương pháp này với một tĩnh nhập khẩu. Ngược lại với giải pháp của Holger, bạn có thể hưởng lợi từ các hoạt động luồng khác nhau, điều này có thể làm cho mã hiện tại trở nên đơn giản hơn. Dưới đây là một ví dụ:

Map<...> map = enumerationAsStream(enumeration) 
    .filter(Objects::nonNull) 
    .collect(groupingBy(...)); 
+0

Tôi nghĩ cả hai đều bổ sung cho nhau giống như 'list.forEach (…)' và 'list.stream(). ⟨stream ops⟩ .forEach (…) '. – Holger

+1

Đây không phải là một phần của JDK? – Nick

+0

'public static Stream enumerationAsStream (Liệt kê e) { trả về Bộ sưu tập.list (e) .stream(); } 'sẽ làm tương tự, nhưng đơn giản hơn nhiều. –

8

Bạn có thể sử dụng sự kết hợp sau đây của các chức năng tiêu chuẩn:

StreamSupport.stream(Spliterators.spliteratorUnknownSize(CollectionUtils.toIterator(enumeration), Spliterator.IMMUTABLE), parallel) 

Bạn cũng có thể thêm các đặc điểm giống như NONNULL hay DISTINCT.

Sau khi áp dụng nhập khẩu tĩnh này sẽ trở nên dễ đọc hơn:

stream(spliteratorUnknownSize(toIterator(enumeration), IMMUTABLE), false) 

bây giờ bạn có một tiêu chuẩn Suối Java 8 được sử dụng trong bất kỳ cách nào! Bạn có thể vượt qua true để xử lý song song.

Để chuyển đổi từ Enumeration để Iterator sử dụng bất kỳ:

  • CollectionUtils.toIterator() từ mùa xuân 3,2 hoặc bạn có thể sử dụng
  • IteratorUtils.asIterator() từ Apache Commons Bộ sưu tập 3.2
  • Iterators.forEnumeration() từ Google Ổi
+0

Bộ sưu tập từ đâu đến? Dường như không có trong JDK. – Martin

+0

@Martin, có vẻ như là 'org.apache.commons.collections.CollectionUtils'. – Vadzim

+0

@Vadzim Tôi đã kiểm tra [Bộ sưu tập của Apache Commons] (https://commons.apache.org/proper/commons-collections/) 1.0, 2.0, 2.1.1, 3.2.1 và 4.0, nhưng không có lớp nào có tên CollectionUtils chứa một phương thức đặt tên toIterator. – Martin

42

Kể từ Java-9 sẽ có phương pháp mặc định mới Enumeration.asIterator() mà sẽ làm cho giải pháp Java tinh khiết đơn giản:

nets.asIterator().forEachRemaining(iface -> { ... }); 
+1

Tham khảo: https://bugs.openjdk.java.net/browse/JDK-8072726 –

1

Đối với Java 8 việc chuyển đổi đơn giản nhất của liệt kê để dòng là:

Collections.list(NetworkInterface.getNetworkInterfaces()).stream()

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