Di Java 8, ada Stream.collect
yang memungkinkan agregasi pada koleksi. Di Kotlin, ini tidak ada dengan cara yang sama, selain mungkin sebagai kumpulan fungsi ekstensi di stdlib. Tetapi tidak jelas apa persamaan untuk kasus penggunaan yang berbeda.
Sebagai contoh, di bagian atas JavaDocCollectors
adalah contoh yang ditulis untuk Java 8, dan ketika porting mereka ke Kolin Anda tidak dapat menggunakan kelas Java 8 ketika pada versi JDK yang berbeda, sehingga kemungkinan mereka harus ditulis secara berbeda.
Dalam hal sumber daya yang secara online menunjukkan contoh koleksi Kotlin, mereka biasanya sepele dan tidak benar-benar dibandingkan dengan kasus penggunaan yang sama. Apa contoh bagus yang benar-benar cocok dengan kasus-kasus seperti yang didokumentasikan untuk Java 8 Stream.collect
? Daftarnya ada:
- Akumulasi nama menjadi Daftar
- Akumulasi nama menjadi TreeSet
- Konversi elemen menjadi string dan menggabungkannya, dipisahkan dengan koma
- Hitung jumlah gaji karyawan
- Kelompokkan karyawan menurut departemen
- Hitung jumlah gaji berdasarkan departemen
- Partisi siswa menjadi lulus dan gagal
Dengan detail di JavaDoc yang ditautkan di atas.
Catatan: pertanyaan ini sengaja ditulis dan dijawab oleh penulis ( Pertanyaan yang Dijawab Sendiri ), sehingga jawaban idiomatis untuk topik Kotlin yang umum diajukan hadir dalam SO. Juga untuk memperjelas beberapa jawaban lama yang ditulis untuk huruf-huruf Kotlin yang tidak akurat untuk Kotlin saat ini.
sumber
collect(Collectors.toList())
atau serupa, Anda mungkin mendapatkan masalah ini: stackoverflow.com/a/35722167/3679676 (masalah, dengan penyelesaian)Jawaban:
Ada fungsi di stdlib Kotlin untuk rata-rata, menghitung, membedakan, memfilter, menemukan, mengelompokkan, bergabung, memetakan, min, maks, mempartisi, mengiris, menyortir, menjumlahkan, menjumlahkan, ke / dari array, ke / dari daftar, ke / dari peta , persatuan, ko-iterasi, semua paradigma fungsional, dan banyak lagi. Jadi Anda dapat menggunakannya untuk membuat 1-liner kecil dan tidak perlu menggunakan sintaks Java 8 yang lebih rumit.
Saya pikir satu-satunya hal yang hilang dariCollectors
kelas Java 8 built-in adalah peringkasan (tetapi dalam jawaban lain untuk pertanyaan ini adalah solusi sederhana) .Satu hal yang hilang dari keduanya adalah batching by count, yang terlihat pada jawaban Stack Overflow lainnya dan memiliki jawaban yang sederhana juga. Kasus lain yang menarik adalah ini juga dari Stack Overflow: Cara idiomatis untuk menumpahkan urutan menjadi tiga daftar menggunakan Kotlin . Dan jika Anda ingin membuat sesuatu sepertiStream.collect
untuk tujuan lain, lihat Custom Stream.collect di KotlinEDIT 11.08.2017: Operasi pengumpulan chunked / windowed ditambahkan di kotlin 1.2 M2, lihat https://blog.jetbrains.com/kotlin/2017/08/kotlin-1-2-m2-is-out/
Itu selalu baik untuk mengeksplorasi Referensi API untuk kotlin.collections secara keseluruhan sebelum membuat fungsi baru yang mungkin sudah ada di sana.
Berikut adalah beberapa konversi dari
Stream.collect
contoh Java 8 ke yang setara di Kotlin:Akumulasi nama menjadi Daftar
Konversi elemen menjadi string dan menggabungkannya, dipisahkan dengan koma
Hitung jumlah gaji karyawan
Kelompokkan karyawan menurut departemen
Hitung jumlah gaji berdasarkan departemen
Partisi siswa menjadi lulus dan gagal
Nama anggota laki-laki
Kelompokkan nama anggota dalam daftar berdasarkan gender
Saring daftar ke daftar lain
Menemukan string terpendek daftar
Menghitung item dalam daftar setelah filter diterapkan
dan seterusnya ... Dalam semua kasus, tidak ada lipatan khusus, pengurangan, atau fungsi lain yang diperlukan untuk meniru
Stream.collect
. Jika Anda memiliki kasus penggunaan lebih lanjut, tambahkan dalam komentar dan kami dapat melihat!Tentang kemalasan
Jika Anda ingin malas memproses rantai, Anda dapat mengonversi ke
Sequence
menggunakanasSequence()
sebelum rantai. Pada akhir rantai fungsi, Anda biasanya berakhir denganSequence
juga. Maka Anda dapat menggunakantoList()
,toSet()
,toMap()
atau beberapa fungsi lain untuk mewujudkanSequence
di akhir.Mengapa tidak ada Tipe?!?
Anda akan melihat contoh Kotlin tidak menentukan jenisnya. Ini karena Kotlin memiliki inferensi tipe penuh dan benar-benar tipe aman pada waktu kompilasi. Lebih dari Java karena juga memiliki jenis nullable dan dapat membantu mencegah NPE yang ditakuti. Jadi ini di Kotlin:
sama dengan:
Karena Kotlin tahu apa
people
adalah, dan bahwapeople.age
adalahInt
karena itu ekspresi filter hanya memungkinkan perbandingan keInt
, dan yangpeople.name
merupakanString
karenanyamap
langkah menghasilkanList<String>
(dibacaList
dariString
).Sekarang, jika
people
mungkinnull
, as-in aList<People>?
then:Mengembalikan nilai
List<String>?
yang perlu dicentang nol ( atau menggunakan salah satu operator Kotlin lain untuk nilai yang dapat dibatalkan , lihat cara idiomatik Kotlin ini untuk menangani nilai yang dapat dibatalkan dan juga cara Idiomatik menangani daftar kosong atau kosong di Kotlin )Lihat juga:
sumber
Untuk contoh tambahan, berikut adalah semua contoh dari Java 8 Stream Tutorial yang dikonversi ke Kotlin. Judul setiap contoh, berasal dari artikel sumber:
Bagaimana stream bekerja
Berbagai Jenis Streaming # 1
atau, buat fungsi ekstensi pada String yang disebut ifPresent:
Lihat juga:
apply()
fungsiLihat juga: Fungsi Ekstensi
Lihat juga:
?.
Operator Panggilan Aman , dan secara umum tidak dapat dibatalkan: Di Kotlin, apa cara idiomatis untuk menangani nilai yang dapat dibatalkan, merujuk atau mengubahnyaBerbagai Jenis Streaming # 2
Berbagai Jenis Streaming # 3
Berbagai Jenis Streaming # 4
Berbagai Jenis Streaming # 5
Berbagai Jenis Streaming # 6
Berbagai Jenis Streaming # 7
Mengapa Memesan Masalah?
Bagian Tutorial Streaming Java 8 ini sama untuk Kotlin dan Java.
Menggunakan Kembali Streaming
Di Kotlin, itu tergantung pada jenis koleksinya apakah dapat dikonsumsi lebih dari satu kali. A
Sequence
menghasilkan iterator baru setiap kali, dan kecuali jika menyatakan "gunakan hanya sekali", it dapat mereset ke awal setiap kali itu ditindaklanjuti. Karenanya sementara yang berikut ini gagal di aliran Java 8, tetapi berfungsi di Kotlin:Dan di Jawa untuk mendapatkan perilaku yang sama:
Oleh karena itu di Kotlin penyedia data memutuskan apakah ia dapat mengatur ulang dan menyediakan iterator baru atau tidak. Tetapi jika Anda ingin secara sengaja membatasi
Sequence
iterasi satu kali, Anda dapat menggunakanconstrainOnce()
fungsiSequence
sebagai berikut:Operasi Lanjutan
Kumpulkan contoh # 5 (ya, saya melewatkan yang sudah ada di jawaban lain)
Dan sebagai catatan tambahan, di Kotlin kita dapat membuat kelas data sederhana dan membuat contoh data tes sebagai berikut:
Kumpulkan contoh # 6
Oke, kasus yang lebih menarik di sini untuk Kotlin. Pertama, jawaban yang salah untuk mengeksplorasi variasi pembuatan
Map
dari koleksi / urutan:Dan sekarang untuk jawaban yang benar:
Kami hanya perlu bergabung dengan nilai yang cocok untuk menciutkan daftar dan menyediakan transformator
jointToString
untuk berpindah dariPerson
instance kePerson.name
.Kumpulkan contoh # 7
Oke, yang ini bisa dengan mudah dilakukan tanpa kebiasaan
Collector
, jadi mari kita selesaikan dengan cara Kotlin, lalu buat contoh baru yang menunjukkan cara melakukan proses serupaCollector.summarizingInt
yang tidak ada di Kotlin.Bukan salah saya, mereka mengambil contoh sepele !!! Oke, ini
summarizingInt
metode baru untuk Kotlin dan sampel yang cocok:Contoh Meringkas
Tetapi lebih baik untuk membuat fungsi ekstensi, 2 sebenarnya untuk mencocokkan gaya di Kotlin stdlib:
Sekarang Anda memiliki dua cara untuk menggunakan
summarizingInt
fungsi - fungsi baru :Dan semua ini menghasilkan hasil yang sama. Kami juga dapat membuat ekstensi ini untuk bekerja pada
Sequence
dan untuk tipe primitif yang sesuai.Untuk bersenang-senang, bandingkan kode Java JDK vs kode kustom Kotlin yang diperlukan untuk mengimplementasikan ringkasan ini.
sumber
.map { it.substring(1).toInt() }
: seperti yang Anda tahu tipe yang disimpulkan adalah salah satu kekuatan kotlin.Ada beberapa kasus di mana sulit untuk menghindari panggilan
collect(Collectors.toList())
atau yang serupa. Dalam kasus tersebut, Anda dapat lebih cepat mengubah ke setara Kotlin menggunakan fungsi ekstensi seperti:Kemudian Anda dapat dengan mudah
stream.toList()
ataustream.asSequence()
untuk kembali ke API Kotlin. Sebuah kasus sepertiFiles.list(path)
memaksa Anda menjadiStream
saat Anda mungkin tidak menginginkannya, dan ekstensi ini dapat membantu Anda untuk beralih kembali ke koleksi standar dan API Kotlin.sumber
Lebih lanjut tentang kemalasan
Mari kita ambil contoh solusi untuk "Hitung jumlah gaji berdasarkan departemen" yang diberikan oleh Jayson:
Untuk membuat ini malas (yaitu menghindari membuat peta perantara di
groupBy
langkah), itu tidak mungkin untuk digunakanasSequence()
. Sebaliknya, kita harus menggunakangroupingBy
danfold
mengoperasikan:Bagi sebagian orang ini bahkan mungkin lebih mudah dibaca, karena Anda tidak berurusan dengan entri peta:
it.value
bagian dalam solusi itu membingungkan bagi saya juga pada awalnya.Karena ini adalah kasus umum dan kami memilih untuk tidak menulis
fold
setiap kali, mungkin lebih baik memberikansumBy
fungsi generik padaGrouping
:sehingga kita bisa menulis:
sumber