Saya memiliki kode berikut:
Stream<String> lines = reader.lines();
Jika fist string sama dengan "email"
saya ingin menghapus string pertama dari Stream. Untuk string lain dari aliran saya tidak perlu cek ini.
Bagaimana saya bisa mencapainya?
PS
Tentu saya bisa mengubahnya ke daftar, lalu gunakan sekolah tua untuk loop tetapi lebih lanjut saya perlu streaming lagi.
java
java-stream
java-11
gstackoverflow
sumber
sumber
skip(long n)
yang melewatkann
elemen pertama , tapi saya tidak tahu apakah Anda bisa mengkondisikannya ...stream.dropWhile(s -> s.equals("email"));
Jawaban:
Sementara pembaca akan berada dalam kondisi yang tidak ditentukan setelah Anda membangun aliran garis dari itu, itu dalam keadaan yang terdefinisi dengan baik sebelum Anda melakukannya.
Jadi kamu bisa melakukannya
Yang merupakan solusi terbersih menurut saya. Perhatikan bahwa ini tidak sama dengan Java 9
dropWhile
, yang akan turun lebih dari satu baris jika cocok.sumber
Jika Anda tidak dapat memiliki daftar dan harus melakukannya hanya dengan
Stream
, Anda dapat melakukannya dengan variabel.Masalahnya adalah Anda hanya bisa menggunakan variabel jika "final" atau "efektif final" sehingga Anda tidak dapat menggunakan boolean literal. Anda masih dapat melakukannya dengan
AtomicBoolean
:Catatan: Saya tidak suka menggunakan "variabel eksternal"
Stream
karena efek samping adalah praktik buruk dalam paradigma pemrograman fungsional. Pilihan yang lebih baik dipersilakan.sumber
compareAndSet
adalah cara yang sangat elegan untuk mengatur dan mendapatkan bendera pada saat yang sama, bagus.stream.filter(!first.compareAndSet(true, false) || !s.equals("email"))
meski bisa diperdebatkan.predicate
harus statelessAtomicBoolean
sini adalah untuk memenuhi aliran paralel (seperti penggunaan yangcompareAndSet
disarankan) maka ini sepenuhnya salah karena hanya akan bekerja jika aliran berurutan. Jika Anda menggunakan teknik denganstream.sequential().filter(...)
namun saya setuju itu akan berhasil.Untuk menghindari memeriksa kondisi pada setiap baris file, saya cukup membaca dan memeriksa baris pertama secara terpisah, kemudian jalankan pipeline pada sisa baris tanpa memeriksa kondisi:
Lebih sederhana di Java 9+:
sumber
Stream.ofNullable(first).filter(not("email"::equals))
Jawaban @rnouds benar. Anda dapat membuat satu aliran untuk baris pertama dan kemudian membandingkannya seperti di bawah ini,
sumber
limit(0)
pastilah seharusnyalimit(1)
....limit(0).filter(line -> !line.startsWith("email"))
tidak masuk akal. Predikat tidak akan pernah dievaluasi. Untuk sumber aliran yang mampu mereproduksi aliran, kombinasi darilimit(1)
yang pertama danskip(1)
yang kedua akan benar. Untuk sumber streaming seperti pembaca, tidaklimit(1)
juga tidaklimit(0)
akan berfungsi. Anda baru saja mengubah baris mana yang ditelan tanpa syarat. Bahkan jika Anda menemukan kombinasi yang melakukan hal yang diinginkan, itu akan didasarkan pada perilaku tergantung implementasi yang tidak ditentukan.Untuk memfilter elemen berdasarkan indeksnya, Anda dapat menggunakan
AtomicInteger
untuk menyimpan dan menambah indeks saat memprosesStream
:Pendekatan ini memungkinkan untuk menyaring elemen pada indeks apa pun, tidak hanya yang pertama.
sumber
Sedikit lebih berbelit-belit, mendapat inspirasi dari cuplikan ini .
Anda dapat membuat
Stream<Integer>
yang akan mewakili indeks dan "zip" dengan AndaStream<String>
untuk membuatStream<Pair<String, Integer>>
Kemudian filter menggunakan indeks dan petakan kembali ke a
Stream<String>
sumber
Berikut ini contoh dengan
Collectors.reducing
. Namun pada akhirnya tetap membuat daftar.sumber
Coba ini:
sumber