Apakah ada operasi streaming Java 8 yang membatasi a (berpotensi tak terbatas) Stream
hingga elemen pertama gagal mencocokkan predikat?
Di Java 9 kita dapat menggunakan takeWhile
seperti pada contoh di bawah ini untuk mencetak semua angka kurang dari 10.
IntStream
.iterate(1, n -> n + 1)
.takeWhile(n -> n < 10)
.forEach(System.out::println);
Karena tidak ada operasi seperti itu di Java 8, apa cara terbaik untuk mengimplementasikannya secara umum?
java
java-8
java-stream
MForster
sumber
sumber
IntStream.iterate(1, n->n<10, n->n+1).forEach(System.out::print);
Jawaban:
Operasi semacam itu seharusnya dimungkinkan dengan Java 8
Stream
, tetapi itu tidak dapat dilakukan dengan efisien - misalnya, Anda tidak dapat selalu memparalelkan operasi seperti itu, karena Anda harus melihat elemen-elemen secara berurutan.API tidak menyediakan cara mudah untuk melakukannya, tetapi apa yang mungkin cara paling sederhana adalah dengan mengambil
Stream.iterator()
, membungkusnya denganIterator
implementasi "take-while", dan kemudian kembali ke aSpliterator
dan kemudian aStream
. Atau - mungkin - bungkusSpliterator
, meskipun itu tidak dapat dipecah lagi dalam implementasi ini.Berikut ini implementasi yang belum teruji
takeWhile
padaSpliterator
:sumber
Operasi
takeWhile
dandropWhile
telah ditambahkan ke JDK 9. Kode contoh Andaakan berperilaku tepat seperti yang Anda harapkan ketika dikompilasi dan dijalankan di bawah JDK 9.
JDK 9 telah dirilis. Ini tersedia untuk diunduh di sini: http://jdk.java.net/9/
sumber
takeWhile
/dropWhile
: download.java.net/jdk9/docs/api/java/util/stream/Stream.htmltakeWhile
dandropWhile
bukannyalimitWhile
danskipWhile
, untuk konsistensi dengan API yang ada?takeWhile
dandropWhile
cukup luas, terjadi di Scala, Python, Groovy, Ruby, Haskell, dan Clojure. Asimetri denganskip
danlimit
tidak menguntungkan. Mungkinskip
danlimit
seharusnya dipanggildrop
dantake
, tetapi itu tidak seintuitif kecuali Anda sudah terbiasa dengan Haskell.dropXXX
dantakeXXX
istilah yang lebih populer tapi saya pribadi bisa hidup dengan lebih banyak SQL-esquelimitXXX
danskipXXX
. Saya menemukan asimetri baru ini jauh lebih membingungkan daripada pilihan istilah individu ... :) (btw: Scala juga punyadrop(int)
dantake(int)
)allMatch()
adalah fungsi hubungan arus pendek, sehingga Anda dapat menggunakannya untuk menghentikan pemrosesan. Kerugian utama adalah Anda harus melakukan tes dua kali: sekali untuk melihat apakah Anda harus memprosesnya, dan sekali lagi untuk melihat apakah akan terus berjalan.sumber
Stream.allMatch()
adalah operasi hubungan arus pendek . Jadi ini akan selesai bahkan pada aliran infinite sepertiIntStream.iterate()
. Tentu saja, dalam retrospeksi, ini adalah optimasi yang masuk akal.peek
. Jika saya bertemu bulan depan, saya akan bertanya-tanya mengapa programmer sebelum saya memeriksa apakahallMatch
dan kemudian mengabaikan jawabannya.Sebagai tindak lanjut dari jawaban @StuartMarks . Pustaka StreamEx saya memiliki
takeWhile
operasi yang kompatibel dengan implementasi JDK-9 saat ini. Ketika berjalan di bawah JDK-9 itu hanya akan mendelegasikan ke implementasi JDK (melaluiMethodHandle.invokeExact
yang sangat cepat). Saat berjalan di bawah JDK-8, implementasi "polyfill" akan digunakan. Jadi, menggunakan perpustakaan saya masalahnya bisa diselesaikan seperti ini:sumber
takeWhile
adalah salah satu fungsi yang disediakan oleh perpustakaan protonpack .sumber
Pembaruan: Java 9
Stream
sekarang hadir dengan metode takeWhile .Tidak perlu peretasan atau solusi lain. Gunakan saja itu!
Saya yakin ini bisa sangat ditingkatkan: (seseorang mungkin bisa membuat thread-safe mungkin)
Peretasan pasti ... Tidak elegan - tetapi berhasil ~: D
sumber
Anda dapat menggunakan java8 + rxjava .
sumber
Sebenarnya ada 2 cara untuk melakukannya di Java 8 tanpa perpustakaan tambahan atau menggunakan Java 9.
Jika Anda ingin mencetak angka dari 2 hingga 20 pada konsol Anda dapat melakukan ini:
atau
Output dalam kedua kasus:
Tidak ada yang disebutkan anyMatch belum. Ini adalah alasan untuk posting ini.
sumber
Ini adalah sumber yang disalin dari JDK 9 java.util.stream.Stream.takeWhile (Predikat). Sedikit perbedaan untuk bekerja dengan JDK 8.
sumber
Ini adalah versi yang dilakukan pada int - seperti yang ditanyakan dalam pertanyaan
Pemakaian:
Berikut kode untuk StreamUtil:
sumber
Pergi untuk mendapatkan perpustakaan AbacusUtil . Ini menyediakan API persis yang Anda inginkan dan banyak lagi:
Deklarasi : Saya pengembang AbacusUtil.
sumber
Anda tidak dapat membatalkan aliran kecuali dengan operasi terminal hubungan pendek, yang akan membuat beberapa nilai aliran tidak diproses terlepas dari nilainya. Tetapi jika Anda hanya ingin menghindari operasi pada aliran Anda dapat menambahkan transformasi dan filter ke aliran:
Itu mengubah aliran hal-hal menjadi nol ketika hal-hal memenuhi beberapa kondisi, lalu menyaring nol. Jika Anda ingin menikmati efek samping, Anda dapat mengatur nilai kondisi menjadi true setelah beberapa hal ditemukan, sehingga semua hal berikutnya disaring terlepas dari nilainya. Tetapi bahkan jika tidak, Anda dapat menyimpan banyak pemrosesan (jika tidak semuanya) dengan memfilter nilai dari aliran yang tidak ingin Anda proses.
sumber
Bahkan saya memiliki persyaratan yang sama - meminta layanan web, jika gagal, coba lagi 3 kali. Jika gagal bahkan setelah banyak percobaan ini, kirim pemberitahuan email. Setelah banyak googling,
anyMatch()
datang sebagai penyelamat. Kode sampel saya sebagai berikut. Dalam contoh berikut, jika metode webServiceCall mengembalikan true di iterasi pertama itu sendiri, streaming tidak beralih lebih jauh seperti yang kita sebutanyMatch()
. Saya percaya, inilah yang Anda cari.sumber
Jika Anda tahu persis jumlah repitisi yang akan dilakukan, Anda bisa melakukannya
sumber
alih-alih puncak, Anda dapat menggunakan mapToObj untuk mengembalikan objek atau pesan akhir
sumber
Jika Anda memiliki masalah yang berbeda, solusi yang berbeda mungkin diperlukan tetapi untuk masalah Anda saat ini, saya hanya akan pergi dengan:
sumber
Mungkin sedikit keluar dari topik tetapi ini yang kita miliki
List<T>
alih - alihStream<T>
.Pertama, Anda perlu memiliki
take
metode util. Metode ini mengambiln
elemen pertama :itu hanya berfungsi seperti
scala.List.take
sekarang akan cukup mudah untuk menulis
takeWhile
metode berdasarkantake
kerjanya seperti ini:
implementasi ini mengulangi daftar sebagian untuk beberapa kali tetapi tidak menambah
O(n^2)
operasi. Harapan itu bisa diterima.sumber
Saya punya solusi cepat lain dengan menerapkan ini (yang sebenarnya tidak bersih, tetapi Anda tahu):
sumber
current
tidak.equals(e)
, Anda akan mendapatkan loop tanpa akhir. Keduanya bahkan jika Anda kemudian menerapkan mis.limit(1)
. Itu jauh lebih buruk daripada 'najis' .Ini adalah upaya saya hanya menggunakan perpustakaan Java Stream.
sumber
filter
predikat seharusnya tanpa kewarganegaraan.System.out.println
adalah efek samping.