Saat menggunakan iterasi eksternal di atas Iterable
kami menggunakan break
atau return
dari peningkatan untuk-setiap loop sebagai:
for (SomeObject obj : someObjects) {
if (some_condition_met) {
break; // or return obj
}
}
Bagaimana kita bisa break
atau return
menggunakan iterasi internal dalam ekspresi Java 8 lambda seperti:
someObjects.forEach(obj -> {
//what to do here?
})
for
pernyataan nyata .forEach()
. Solusinya adalah tidak baik, tetapi adalah mungkin. Lihat jawaban saya di bawah ini.if
kondisi sederhana di dalamforEach
akan melakukan trik.Jawaban:
Jika Anda membutuhkan ini, Anda tidak boleh menggunakan
forEach
, tetapi salah satu metode lain yang tersedia di stream; yang mana, tergantung pada apa tujuan Anda.Misalnya, jika tujuan dari loop ini adalah untuk menemukan elemen pertama yang cocok dengan beberapa predikat:
(Catatan: Ini tidak akan mengulangi seluruh koleksi, karena aliran dievaluasi malas - itu akan berhenti di objek pertama yang cocok dengan kondisi).
Jika Anda hanya ingin tahu apakah ada elemen dalam koleksi yang kondisinya benar, Anda bisa menggunakan
anyMatch
:sumber
return
pernyataan dari suatufindSomething
metode.break
lebih biasanya dikaitkan dengan take -jenis operasi.forEach
untuk ini; Anda harus menggunakan metode lain yang lebih tepat.forEach
" secara teknis salah. Saya juga lebih suka solusi Anda, namun saya bisa membayangkan menggunakan kasus-kasus di mana solusi yang disediakan dalam jawaban saya lebih disukai: ketika loop harus diakhiri karena pengecualian nyata . Saya setuju bahwa Anda seharusnya tidak secara umum menggunakan pengecualian untuk mengontrol arus.Ini adalah mungkin bagi
Iterable.forEach()
(tetapi tidak andal denganStream.forEach()
). Solusinya adalah tidak baik, tetapi adalah mungkin.PERINGATAN : Anda tidak boleh menggunakannya untuk mengendalikan logika bisnis, tetapi murni untuk menangani situasi luar biasa yang terjadi selama eksekusi
forEach()
. Seperti sumber daya tiba-tiba berhenti diakses, salah satu objek yang diproses melanggar kontrak (mis. Kontrak mengatakan bahwa semua elemen dalam aliran tidak bolehnull
tiba-tiba dan tidak terduga salah satunyanull
) dll.Menurut dokumentasi untuk
Iterable.forEach()
:Jadi Anda melempar pengecualian yang akan segera memecah loop internal.
Kode akan menjadi seperti ini - saya tidak bisa mengatakan saya menyukainya tetapi berfungsi. Anda membuat kelas Anda sendiri
BreakException
yang memanjangRuntimeException
.Perhatikan bahwa
try...catch
adalah tidak sekitar ekspresi lambda, melainkan sekitar seluruhforEach()
metode. Untuk membuatnya lebih terlihat, lihat transkripsi kode berikut yang menunjukkan lebih jelas:sumber
Stream.forEach
tidak tidak memberikan jaminan yang kuat yang sama tentang pengecualian yang disampaikan ke pemanggil, sehingga melemparkan pengecualian tidak dijamin untuk bekerja dengan cara ini untukStream.forEach
.Iterable.forEach()
, tapi saya menambahkan poin Anda ke teks saya hanya untuk kelengkapan.Pengembalian dalam lambda sama dengan melanjutkan di masing-masing, tetapi tidak ada yang setara dengan istirahat. Anda bisa melakukan pengembalian untuk melanjutkan:
sumber
Di bawah ini Anda menemukan solusi yang saya gunakan dalam sebuah proyek. Sebaliknya
forEach
gunakan sajaallMatch
:sumber
Entah Anda perlu menggunakan metode yang menggunakan predikat yang menunjukkan apakah akan terus berjalan (jadi malah ada istirahat) atau Anda perlu melempar pengecualian - yang tentu saja merupakan pendekatan yang sangat jelek.
Jadi Anda bisa menulis
forEachConditional
metode seperti ini:Daripada
Predicate<T>
, Anda mungkin ingin mendefinisikan antarmuka fungsional Anda sendiri dengan metode umum yang sama (sesuatu mengambilT
dan mengembalikan abool
) tetapi dengan nama yang menunjukkan harapan lebih jelas -Predicate<T>
tidak ideal di sini.sumber
takeWhile
operasi klasik , dan pertanyaan ini hanyalah salah satu dari yang menunjukkan seberapa besar kekurangannya dalam API Streams.Anda dapat menggunakan java8 + rxjava .
sumber
Untuk kinerja maksimal dalam operasi paralel gunakan findAny () yang mirip dengan findFirst ().
Namun Jika hasil yang stabil diinginkan, gunakan findFirst () sebagai gantinya.
Perhatikan juga bahwa pola yang cocok (anyMatch () / allMatch) hanya akan mengembalikan boolean, Anda tidak akan mendapatkan objek yang cocok.
sumber
Perbarui dengan Java 9+ dengan
takeWhile
:sumber
Saya telah mencapai sesuatu seperti ini
sumber
Anda dapat mencapainya menggunakan campuran peek (..) dan anyMatch (..).
Menggunakan contoh Anda:
Atau cukup tulis metode util generik:
Dan kemudian gunakan, seperti ini:
sumber
Bagaimana dengan yang ini:
Di mana
BooleanWrapper
kelas Anda harus menerapkan untuk mengontrol aliran.sumber
!condition.ok()
, namun itu tidak mencegahforEach()
perulangan atas semua objek. Jika bagian yang lambat adalahforEach()
iterasi dan bukan penggunanya (misalnya, ia mendapatkan objek dari koneksi jaringan yang lambat), maka pendekatan ini tidak terlalu berguna.Ini hanya akan melakukan operasi di mana ia menemukan kecocokan, dan setelah menemukan kecocokan itu menghentikan iterasi.
sumber
Saya sarankan menggunakan anyMatch. Contoh:-
Anda dapat merujuk posting ini untuk memahami anyMatch: - https://beginnersbook.com/2017/11/java-8-stream-anymatch-example/
sumber