Kami telah menggunakan metode Collect() beberapa kali sebelumnya untuk menggabungkan elemen yang dikembalikan oleh Stream ke dalam ArrayList. Ini adalah operasi pengurangan, yang berguna untuk mengubah suatu koleksi menjadi tipe lain (biasanya koleksi yang dapat diubah). Fungsi collector(), jika digunakan bersama dengan beberapa metode di kelas alat Collectors, dapat memberikan kemudahan yang luar biasa, seperti yang akan kami perkenalkan di bagian ini.
Mari kita lanjutkan menggunakan daftar Person sebelumnya sebagai contoh untuk melihat apa yang dapat dilakukan metodecollect(). Misalkan kita ingin mencari semua orang yang berusia lebih dari 20 tahun dari daftar aslinya. Berikut adalah versi yang diimplementasikan menggunakan mutabilitas dan metode forEach():
Copy kode kodenya sebagai berikut:
Daftar<Orang> lebih tuaThan20 = Daftar Array baru<>();
.filter(orang -> orang.getAge() > 20)
.forEach(orang -> lebih tuaDari20.tambahkan(orang)); System.out.println("Orang yang lebih tua dari 20 tahun: " + lebih tuaDari20);
Kami menggunakan metode filter() untuk memfilter semua orang yang berusia lebih dari 20 tahun dari daftar. Kemudian, pada metode forEach, kita menambahkan elemen ke ArrayList yang telah diinisialisasi sebelumnya. Mari kita lihat keluaran kode ini terlebih dahulu, lalu rekonstruksi lagi nanti.
Copy kode kodenya sebagai berikut:
Orang yang berusia lebih dari 20 tahun: [Sara - 21, Jane - 21, Greg - 35]
Output program sudah benar, namun masih ada sedikit masalah. Pertama, menambahkan elemen ke koleksi adalah operasi tingkat rendah - ini adalah keharusan, bukan deklaratif. Jika kita ingin mengubah iterasi ini menjadi konkuren, kita harus mempertimbangkan masalah keamanan thread - variabilitas membuatnya sulit untuk diparalelkan. Untungnya, masalah ini dapat diselesaikan dengan mudah menggunakan metode Collect(). Mari kita lihat bagaimana hal ini dicapai.
Metode Collect() menerima Aliran dan mengumpulkannya ke dalam wadah hasil. Untuk melakukan ini, ia perlu mengetahui tiga hal:
+ Cara membuat wadah hasil (misalnya, menggunakan metode ArrayList::new) + Cara menambahkan satu elemen ke wadah (misalnya, menggunakan metode ArrayList::add) + Cara menggabungkan satu kumpulan hasil ke kumpulan hasil lainnya (misalnya, menggunakan metode ArrayList: :addAll)
Item terakhir tidak diperlukan untuk operasi serial; kode ini dirancang untuk mendukung operasi serial dan paralel.
Kami menyediakan operasi ini ke metode pengumpulan dan membiarkannya mengumpulkan aliran yang difilter.
Copy kode kodenya sebagai berikut:
Daftar<Orang> lebih tuaDari20 =
orang.aliran()
.filter(orang -> orang.getAge() > 20)
.collect(ArrayList::baru, ArrayList::tambahkan, ArrayList::addAll);
System.out.println("Orang di atas 20 tahun: " + lebih tua dari 20 tahun);
Hasil dari kode ini sama seperti sebelumnya, namun banyak keuntungan jika ditulis dengan cara ini.
Pertama-tama, metode pemrograman kami lebih fokus dan ekspresif, menyampaikan dengan jelas tujuan pengumpulan hasil ke dalam ArrayList. Parameter pertama dari Collect() adalah pabrik atau produsen, dan parameter selanjutnya adalah operasi yang digunakan untuk mengumpulkan elemen.
Kedua, karena kita tidak melakukan modifikasi eksplisit pada kode, kita dapat dengan mudah melakukan iterasi ini secara paralel. Kami membiarkan perpustakaan yang mendasarinya menangani modifikasi, dan itu akan menangani masalah koordinasi dan keamanan thread, meskipun ArrayList itu sendiri tidak aman untuk thread - kerja bagus.
Jika kondisinya memungkinkan, metodecollect() dapat menambahkan elemen ke subdaftar yang berbeda secara paralel, lalu menggabungkannya ke dalam daftar besar dengan cara yang aman untuk thread (parameter terakhir digunakan untuk operasi penggabungan).
Kita telah melihat bahwa ada banyak manfaat menggunakan metode Collect() dibandingkan menambahkan elemen ke daftar secara manual. Mari kita lihat versi kelebihan beban dari metode ini - lebih sederhana dan nyaman - dibutuhkan Kolektor sebagai parameter. Collector ini adalah antarmuka yang mencakup produsen, penambah, dan penggabung. Pada versi sebelumnya, operasi ini diteruskan ke metode sebagai parameter independen. Kelas alat Collectors menyediakan metode toList yang dapat menghasilkan implementasi Collector untuk menambahkan elemen ke ArrayList. Mari kita ubah kode sebelumnya dan gunakan metodecollect().
Copy kode kodenya sebagai berikut:
Daftar<Orang> lebih tuaDari20 =
orang.aliran()
.filter(orang -> orang.getAge() > 20)
.collect(Collectors.toList());
System.out.println("Orang di atas 20 tahun: " + lebih tua dari 20 tahun);
Versi ringkas metode kumpulkan() kelas alat Kolektor digunakan, namun dapat digunakan dalam lebih dari satu cara. Ada beberapa metode berbeda di kelas alat Kolektor untuk melakukan operasi pengumpulan dan penambahan yang berbeda. Misalnya, selain metode toList(), ada juga metode toSet() yang dapat ditambahkan ke suatu Set, metode toMap() yang dapat digunakan untuk mengumpulkan ke dalam kumpulan nilai kunci, dan metode toMap() yang dapat digunakan untuk mengumpulkan kumpulan nilai kunci. join() metode, yang dapat disambung menjadi sebuah string. Kita juga dapat menggabungkan metode seperti pemetaan(), pengumpulanAndThen(), minBy(), maxBy() dan groupingBy() untuk digunakan.
Mari gunakan metode groupingBy() untuk mengelompokkan orang berdasarkan usia.
Copy kode kodenya sebagai berikut:
Peta<Bilangan Bulat, Daftar<Orang>> peopleByAge =
orang.aliran()
.collect(Collectors.groupingBy(Orang::getAge));
System.out.println("Dikelompokkan berdasarkan umur: " + peopleByAge);
Cukup panggil metodecollect() untuk menyelesaikan pengelompokan. groupingBy() menerima ekspresi lambda atau referensi metode - ini disebut fungsi klasifikasi - dan mengembalikan nilai atribut tertentu dari objek yang perlu dikelompokkan. Berdasarkan nilai yang dikembalikan oleh fungsi kita, elemen dalam konteks pemanggilan ditempatkan ke dalam grup tertentu. Hasil pengelompokannya dapat dilihat pada output:
Copy kode kodenya sebagai berikut:
Dikelompokkan berdasarkan umur: {35=[Greg - 35], 20=[John - 20], 21=[Sara - 21, Jane - 21]}
Orang-orang telah dikelompokkan berdasarkan usia.
Pada contoh sebelumnya kami mengelompokkan orang berdasarkan usia. Varian dari metode groupingBy() dapat dikelompokkan berdasarkan beberapa kondisi. Metode groupingBy() yang sederhana menggunakan pengklasifikasi untuk mengumpulkan elemen. Kolektor groupingBy() umum dapat menentukan kolektor untuk setiap grup. Dengan kata lain, elemen akan melewati pengklasifikasi dan koleksi yang berbeda selama proses pengumpulan, seperti yang akan kita lihat di bawah.
Melanjutkan contoh di atas, kali ini alih-alih mengelompokkan berdasarkan usia, kita hanya mendapatkan nama orang-orang dan mengurutkannya berdasarkan usia.
Copy kode kodenya sebagai berikut:
Peta<Bilangan Bulat, Daftar<String>> nameOfPeopleByAge =
orang.aliran()
.mengumpulkan(
groupingBy(Orang::getAge, pemetaan(Orang::getName, toList())));
System.out.println("Orang dikelompokkan berdasarkan umur: " + nameOfPeopleByAge);
Versi groupingBy() ini menerima dua parameter: yang pertama adalah umur, yang merupakan kondisi untuk pengelompokan, dan yang kedua adalah seorang kolektor, yang merupakan hasil yang dikembalikan oleh fungsi pemetaan(). Semua metode ini berasal dari kelas alat Kolektor dan diimpor secara statis dalam kode ini. Metode pemetaan() menerima dua parameter, satu adalah atribut yang digunakan untuk pemetaan, dan yang lainnya adalah tempat pengumpulan objek, seperti daftar atau kumpulan. Mari kita lihat output dari kode di atas:
Copy kode kodenya sebagai berikut:
Orang yang dikelompokkan berdasarkan umur: {35=[Greg], 20=[John], 21=[Sara, Jane]}
Seperti yang Anda lihat, nama-nama orang telah dikelompokkan berdasarkan usia.
Mari kita lihat operasi kombinasi lagi: kelompokkan berdasarkan huruf pertama nama, lalu pilih orang tertua di setiap grup.
Copy kode kodenya sebagai berikut:
Comparator<Person> byAge = Comparator.comparing(Person::getAge);
Peta<Karakter, Opsional<Orang>> TertuaPersonOfEachLetter =
orang.aliran()
.collect(groupingBy(orang -> orang.getName().charAt(0),
mengurangi(BinaryOperator.maxBy(menurut Usia))));
System.out.println("Orang tertua dari setiap huruf:");
System.out.println(PersonOfEachLetter tertua);
Kami terlebih dahulu mengurutkan nama berdasarkan abjad. Untuk mencapai hal ini, kami meneruskan ekspresi lambda sebagai parameter pertama groupingBy(). Ekspresi lambda ini digunakan untuk mengembalikan huruf pertama dari nama untuk pengelompokan. Parameter kedua tidak lagi memetakan(), namun melakukan operasi pengurangan. Dalam setiap grup, ia menggunakan metode maxBy() untuk mendapatkan elemen terlama dari semua elemen. Sintaksnya terlihat agak membengkak karena banyaknya operasi yang digabungkan, namun keseluruhannya berbunyi seperti ini: Kelompokkan berdasarkan huruf pertama dari nama, lalu turunkan ke yang tertua dalam grup. Pertimbangkan keluaran kode ini, yang mencantumkan orang tertua dalam sekelompok nama yang dimulai dengan huruf tertentu.
Copy kode kodenya sebagai berikut:
Orang tertua dari setiap huruf:
{S=Opsional[Sara - 21], G=Opsional[Greg - 35], J=Opsional[Jane - 21]}
Kita telah merasakan kehebatan metode Collect() dan kelas utilitas Collectors. Dalam dokumentasi resmi IDE atau JDK Anda, luangkan waktu untuk mempelajari kelas alat Kolektor dan pahami berbagai metode yang disediakannya. Selanjutnya kita akan menggunakan ekspresi lambda untuk mengimplementasikan beberapa filter.