Java 8 JDK kullanarak Yinelenebilir Akışa Dönüştür


418

Dönen bir arayüz var java.lang.Iterable<T>.

Bu sonucu Java 8 Stream API'sini kullanarak değiştirmek istiyorum.

Ancak yinelenebilir "akış" yapamaz.

Herhangi bir fikrin bir Akış olarak Listeye dönüştürülmeden nasıl kullanılacağı hakkında bir fikriniz var mı?


2
Yineleyebiliyorsanız, neden durumunu veya değerini kontrol etmek için bir döngü kullanmıyorsunuz?
Afzaal Ahmad Zeeshan

26
@AfzaalAhmadZeeshan çünkü akışlar çok daha iyi
Sleiman Jneidi

1
Söylediğim gibi, bu listede bazı değişiklikler yapmam gerekiyor (filtreler, haritalama). Yeni Java 8 JDK API -> Akışını kullanmak istiyorum. ama yinelenebilir "SteamAble" değil
rayman

myIterable.stream()Var olmayan garip görünüyor !
Josh

7
@Guillaume: Evet, ama Stream.of(iterable)üretiyor Stream<Iterable<Object>>.
Matthias Braun

Yanıtlar:


571

spliteratorUnknownSizeDoğrudan kullanmaktan çok daha iyi bir cevap var , bu hem daha kolay hem de daha iyi bir sonuç alıyor. Iterablebir spliterator()yöntemi vardır, bu yüzden sadece bölücünüzü almak için bunu kullanmalısınız. En kötü durumda, aynı kod (varsayılan uygulama kullanır spliteratorUnknownSize), ancak Iterablezaten bir koleksiyon olduğunuz daha yaygın durumda, daha iyi bir ayırıcı ve dolayısıyla daha iyi akış performansı (belki de iyi paralellik) elde edersiniz. Ayrıca daha az kod:

StreamSupport.stream(iterable.spliterator(), false)
             .filter(...)
             .moreStreamOps(...);

Gördüğünüz gibi, bir akıştan Iterable(ayrıca bu soruya bakın ) bir akış elde etmek çok acı verici değildir.


109
Üzerinde statik bir yöntem iyi Streamolurdu, örneğin Stream.ofIterable(iterable).
robinst

59
@robinst Bu bir ihmal değildi; kasıtlı (ve tartışmalı) bir seçimdi. Sorun şudur ki, bu mevcuttu, onunla birlikte gelen ödünleşimleri anlamadan ona ulaşmak çok kolay olurdu. Yinelenebilir çok soyut olduğu için, böyle bir yöntem mümkün olan en kötü performansa sahip akışla sonuçlanır (paralel destek yok, boyut bilgisi veya özellik yok (yürütme seçeneklerini optimize etmek için kullanılır)). Daha fazla düşünce sonucunu tüm ekosistem genelinde daha iyi API'lere zorlamak. Bu, "XYZ kodu için en iyi olanın" veya "tüm Java kodu için en iyi olanın" karşılaştırmasıydı.
Brian Goetz

2
Açıklamanıza dayanarak, neden Collection.stream () elde ettiğimizi merak ediyorum ama Iterable.stream (). Iterable.stream () (veya Stream.ofIterable ()) 'ı atlamanın gerekçesi, Collection.stream () için eşit olarak geçerlidir.
qualidafial


11
@BrianGoetz Görünüşe göre çoğu insan yukarıda söylediğini anlayabilecek düzeyde değil ya da umursamıyor. basit kodu yalnızca basit API'yı çağırarak yazmak isterler. Öte yandan, bu şeyler (paralel ...) günlük yinelenebilir operasyonların çoğu için önemli olmayabilir.
user_3380739


23

Kolayca bir Streamdışarı Iterableveya oluşturabilirsiniz Iterator:

public static <T> Stream<T> stream(Iterable<T> iterable) {
    return StreamSupport.stream(
        Spliterators.spliteratorUnknownSize(
            iterable.iterator(),
            Spliterator.ORDERED
        ),
        false
    );
}

2
Bu işlevi bir kez yazmanız ve sonra çağırmanız yeterlidir. Neden stream(...)kodunuzu karıştırmak için bir çağrı yapıyorsunuz?
gexicide

1
Bunu yapmak istedim Inline kısa ve zarif .. haklı bir kez bu işlevi yazabilirsiniz .. ama kod bırakarak (ve kod eklemeden). neyse bu cevap doğru çünkü bunu dönüştürmenin yolu bu.
rayman

statik ithal adı geçen fonksiyon. kısa ve zarif. (her zaman şeffaf olmasa da)
14'te

9

JOOL kütüphanesini kullanmanızı öneririm , Seq.seq (yinelenebilir) çağrısının arkasındaki ayırıcı sihrini gizler ve ayrıca bir sürü ek kullanışlı işlevsellik sağlar.


7

Bahsedilen başka bir cevap Guava'nın bunu kullanarak desteği var:

Streams.stream(iterable);

Uygulamanın önerilen diğer cevaplardan biraz farklı bir şey yaptığını vurgulamak istiyorum. Eğer Iterabletür ise, Collectiononlar döküm.

public static <T> Stream<T> stream(Iterable<T> iterable) {
  return (iterable instanceof Collection)
    ? ((Collection<T>) iterable).stream()
    : StreamSupport.stream(iterable.spliterator(), false);
}

public static <T> Stream<T> stream(Iterator<T> iterator) {
  return StreamSupport.stream(
    Spliterators.spliteratorUnknownSize(iterator, 0),
    false
  );
}

5

Bu sınıfı oluşturdum:

public class Streams {
    /**
     * Converts Iterable to stream
     */
    public static <T> Stream<T>  streamOf(final Iterable<T> iterable) {
        return toStream(iterable, false);
    }

    /**
     * Converts Iterable to parallel stream
     */
    public static <T> Stream<T> parallelStreamOf(final Iterable<T> iterable) {
        return toStream(iterable, true);
    }

    private static <T> Stream<T> toStream(final Iterable<T> iterable, final boolean isParallel) {
        return StreamSupport.stream(iterable.spliterator(), isParallel);
    }
}

Bence mükemmel okunabilir çünkü ayırıcılar ve booleans (isParallel) hakkında düşünmek zorunda değilsiniz.


4

Bu sorun için çok basit bir çözüm , bir yöntemi tutan bir Streamable<T>arabirim oluşturmaktır .Iterable<T>default <T> stream()

interface Streamable<T> extends Iterable<T> {
    default Stream<T> stream() {
        return StreamSupport.stream(spliterator(), false);
    }
}

Artık herhangi biri yerine Iterable<T>sadece onları beyan ederek akışa açık hale getirilebilir .implements Streamable<T>Iterable<T>


0

Vavr'ı (eski adıyla Javaslang olarak bilinir) kullanırsanız, bu kadar kolay olabilir:

Iterable i = //...
Stream.ofAll(i);

-1

Java 8 ile ve harici kütüphaneler olmadan bunu yapmanın başka bir yolu:

Stream.concat(collectionA.stream(), collectionB.stream())
      .collect(Collectors.toList())
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.