Saya mencari cara ringkas untuk mengkonversi Iterator
ke Stream
atau lebih khusus untuk "melihat" iterator sebagai aliran.
Untuk alasan kinerja, saya ingin menghindari salinan iterator dalam daftar baru:
Iterator<String> sourceIterator = Arrays.asList("A", "B", "C").iterator();
Collection<String> copyList = new ArrayList<String>();
sourceIterator.forEachRemaining(copyList::add);
Stream<String> targetStream = copyList.stream();
Berdasarkan beberapa saran dalam komentar, saya juga mencoba menggunakan Stream.generate
:
public static void main(String[] args) throws Exception {
Iterator<String> sourceIterator = Arrays.asList("A", "B", "C").iterator();
Stream<String> targetStream = Stream.generate(sourceIterator::next);
targetStream.forEach(System.out::println);
}
Namun, saya mendapatkan NoSuchElementException
(karena tidak ada doa hasNext
)
Exception in thread "main" java.util.NoSuchElementException
at java.util.AbstractList$Itr.next(AbstractList.java:364)
at Main$$Lambda$1/1175962212.get(Unknown Source)
at java.util.stream.StreamSpliterators$InfiniteSupplyingSpliterator$OfRef.tryAdvance(StreamSpliterators.java:1351)
at java.util.Spliterator.forEachRemaining(Spliterator.java:326)
at java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:580)
at Main.main(Main.java:20)
Saya telah melihat StreamSupport
dan Collections
tetapi saya tidak menemukan apa pun.
Stream.generate(iterator::next)
bekerja?Jawaban:
Salah satu caranya adalah dengan membuat Spliterator dari Iterator dan menggunakannya sebagai dasar untuk streaming Anda:
Alternatif yang mungkin lebih mudah dibaca adalah menggunakan Iterable - dan membuat Iterable dari Iterator sangat mudah dengan lambdas karena Iterable adalah antarmuka fungsional:
sumber
sourceIterator.next()
sebelum menggunakan aliran dan Anda akan melihat efeknya (item pertama tidak akan terlihat oleh Stream).Iterable<String> iterable = () -> sourceIterator;
. Saya harus mengakui bahwa saya butuh waktu untuk mengerti.Iterable<T>
adalahFunctionalInterface
yang hanya memiliki satu metode abstrakiterator()
. Begitu() -> sourceIterator
juga ekspresi lambda yang meng-instantiasi sebuahIterable
instance sebagai implementasi anonim.() -> sourceIterator;
adalah bentuk singkat darinew Iterable<>() { @Override public Iterator<String> iterator() { return sourceIterator; } }
Sejak versi 21, perpustakaan Guava menyediakan
Streams.stream(iterator)
Ia melakukan apa yang ditunjukkan oleh jawaban assylias .
sumber
Saran bagus! Inilah pendapat saya yang dapat digunakan kembali:
Dan penggunaan (pastikan untuk mengimpor asStream secara statis):
sumber
Ini dimungkinkan di Java 9.
sumber
.parallel()
stream. Mereka juga tampak sedikit lebih lambat daripada pergiSpliterator
, bahkan untuk penggunaan berurutan.parallel
mungkin funky, kesederhanaannya luar biasa.Buat
Spliterator
dariIterator
menggunakanSpliterators
kelas berisi lebih dari satu fungsi untuk membuat spliterator, misalnya di sini saya menggunakanspliteratorUnknownSize
yang mendapatkan iterator sebagai parameter, lalu buat Streaming menggunakanStreamSupport
sumber
dan gunakan
Streams.stream(iterator)
:sumber
Cara lain untuk melakukan ini di Java 9+ menggunakan Stream :: iterate (T, Predicate, UnaryOperator) :
sumber
Menggunakan
Collections.list(iterator).stream()...
sumber