簡體   English   中英

如何將Java枚舉轉換為流?

[英]How do I turn a Java Enumeration into a Stream?

我有一個第三方庫,它給我一個Enumeration<String> 我希望懶惰地使用該枚舉作為Java 8 Stream ,在其上調用filtermapflatMap的東西。

是否有現有的庫? 我已經引用了Guava和Apache Commons,所以如果其中任何一個都有理想的解決方案。

或者,在保留所有內容的惰性的同時,將Enumeration轉換為Stream的最佳/最簡單方法是什么?

為什么不使用vanilla Java:

Collections.list(enumeration).stream()...

但是,正如@MicahZoltu所提到的,必須考慮枚舉中的項目數,因為Collections.list將首先遍歷枚舉以復制ArrayList的元素。 從那里可以使用常規stream方法。 雖然這對於許多集合流操作來說是常見的,但如果枚舉太大(如無限),這可能會導致問題,因為枚舉必須在列表中進行轉換,然后應該使用此處描述的其他方法。

這個答案已經提供了一個解決方案,它可以從Enumeration創建一個Stream

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

應當強調的是,所產生的Stream 其他任何偷懶Stream ,因為它不會處理任何物品的終端動作已經開始,如果終端操作短路,它會遍歷只有盡可能多的項目之前,需要。

不過,它還有改進的余地。 當有一種直接處理所有元素的方法時,我總是會添加一個forEachRemaining方法。 對於大多數非短路操作, Stream實現將調用所述方法:

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();
                }
                public void forEachRemaining(Consumer<? super T> action) {
                    while(e.hasMoreElements()) action.accept(e.nextElement());
                }
            },
            Spliterator.ORDERED), false);
}

但是,上面的代碼是“使用Iterator因為它是如此熟悉的”反模式的受害者。 創建的Iterator將被包裝到新Spliterator接口的實現中,並沒有直接實現Spliterator優勢:

public static <T> Stream<T> enumerationAsStream(Enumeration<T> e) {
    return StreamSupport.stream(
        new Spliterators.AbstractSpliterator<T>(Long.MAX_VALUE, Spliterator.ORDERED) {
            public boolean tryAdvance(Consumer<? super T> action) {
                if(e.hasMoreElements()) {
                    action.accept(e.nextElement());
                    return true;
                }
                return false;
            }
            public void forEachRemaining(Consumer<? super T> action) {
                while(e.hasMoreElements()) action.accept(e.nextElement());
            }
    }, false);
}

在源代碼級別,此實現與基於Iterator的實現一樣簡單,但消除了從SpliteratorIterator的委派。 它只需要讀者了解新的API。

在Java 9中,可以使用單行將Enumeration轉換為Stream

Enumeration<String> en = ... ;
Stream<String> str = StreamSupport.stream(
    Spliterators.spliteratorUnknownSize(en.asIterator(), Spliterator.ORDERED),
    false
);

(嗯,這是一個相當長的路線。)

如果您不使用Java 9,則可以使用Holger答案中給出的技術手動將Enumeration轉換為Iterator

根據Guava文檔 ,您可以使用Iterators.forEnumeration()方法:

Enumeration<Something> enumeration = ...;

Iterator<SomeThing> iterator = Iterators.forEnumeration(enumeration);

這個問題中 ,它解釋了如何從迭代器獲取流:

Stream<Something> stream = StreamSupport.stream(
    Spliterators.spliteratorUnknownSize(
        iterator, Spliterator.ORDERED),
    false);

在我的StreamEx庫中有一個簡單的方法StreamEx.of(Enumeration)來完成這項工作:

Stream<String> stream = StreamEx.of(enumeration);

請注意,它不僅是@Holger解決方案的快捷方式,而且以不同的方式實現。 特別是,與涉及Spliterators.spliteratorUnknownSize()解決方案相比,它具有明顯更好的並行執行特性。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM