Memahami Spliterator, Kolektor dan Streaming di Jawa 8

143

Saya mengalami kesulitan memahami Streamantarmuka di Java 8, terutama yang berkaitan dengan Spliteratordan Collectorantarmuka. Masalah saya adalah bahwa saya tidak bisa mengerti Spliteratordan Collectorantarmuka belum, dan sebagai hasilnya, Streamantarmuka masih agak tidak jelas bagi saya.

Apa itu a Spliteratordan a Collector, dan bagaimana saya bisa menggunakannya? Jika saya mau menulis sendiri Spliteratoratau Collector(dan mungkin saya sendiri Streamdalam proses itu), apa yang harus saya lakukan dan tidak lakukan?

Saya membaca beberapa contoh yang tersebar di web, tetapi karena semuanya di sini masih baru dan dapat berubah, contoh dan tutorialnya masih sangat jarang.

Victor Stafusa
sumber

Jawaban:

142

Anda seharusnya hampir tidak pernah harus berurusan dengan Spliteratorsebagai pengguna; seharusnya hanya diperlukan jika Anda menulis Collectionsendiri dan juga ingin mengoptimalkan operasi yang diparalelkan.

Untuk apa nilainya, a Spliteratoradalah cara beroperasi di atas elemen-elemen koleksi dengan cara yang mudah untuk memisahkan bagian dari koleksi, misalnya karena Anda memparalelkan dan ingin satu utas untuk bekerja pada satu bagian dari koleksi, satu utas untuk bekerja di bagian lain, dll.

Anda pada dasarnya juga tidak boleh menyimpan nilai tipe Streamke variabel. Streamadalah semacam seperti Iterator, dalam arti ini adalah objek sekali pakai yang hampir selalu Anda gunakan dalam rantai fasih, seperti pada contoh Javadoc:

int sum = widgets.stream()
                  .filter(w -> w.getColor() == RED)
                  .mapToInt(w -> w.getWeight())
                  .sum();

Collectoradalah versi abstrak yang paling umum dan abstrak dari operasi "perkecil" a la map / kurangi; khususnya, perlu mendukung langkah-langkah paralelisasi dan finalisasi. Contoh Collectors meliputi:

  • menjumlahkan, misalnya Collectors.reducing(0, (x, y) -> x + y)
  • Menambahkan StringBuilder, misalnya Collector.of(StringBuilder::new, StringBuilder::append, StringBuilder::append, StringBuilder::toString)
Louis Wasserman
sumber
31
Spliterator juga menyediakan cara untuk mengalirkan Iterable yang bukan Koleksi
Bohemian
2
Maksud saya "operasi pereduksi, dalam arti istilah itu dimaksudkan dalam peta / reduksi"
Louis Wasserman
1
Apakah Collectors.ofmetode lama versi beta sudah dihapus atau saya-saya kehilangan sesuatu? Untuk kelengkapan, (x,y) -> x+ybisa ditulis sebagai Integer::sum.
Jean-François Savard
3
Eh, tidak, maaf, ini Collector.of, bukan Collectors.of.
Louis Wasserman
2
Contoh Kolektor Anda akan lebih bermanfaat jika Anda menjelaskan apa yang dilakukan masing-masing Kolektor Anda.
MiguelMunoz
90

Spliterator pada dasarnya berarti "splitterable Iterator".

Single thread dapat melintasi / memproses seluruh Spliterator itu sendiri, tetapi Spliterator juga memiliki metode trySplit()yang akan "memisahkan" bagian untuk diproses oleh orang lain (biasanya, utas lainnya) - meninggalkan spliterator saat ini dengan lebih sedikit pekerjaan.

Collectormenggabungkan spesifikasi reducefungsi (ketenaran peta-pereduksi), dengan nilai awal, dan fungsi untuk menggabungkan dua hasil (sehingga memungkinkan hasil dari aliran pekerjaan yang terpisah, untuk digabungkan.)

Misalnya, Kolektor paling dasar akan memiliki vaue awal 0, menambahkan bilangan bulat ke hasil yang ada, dan akan 'menggabungkan' dua hasil dengan menambahkannya. Dengan demikian menjumlahkan aliran bilangan bulat yang terpecah.

Lihat:

Thomas W
sumber
nilai untuk menggabungkan dua hasil?
Jason Law
@JasonLaw - diklarifikasi! Terima kasih untuk sarannya.
Thomas W
5

Berikut ini adalah contoh penggunaan kolektor yang telah ditentukan sebelumnya untuk melakukan tugas reduksi yang umum bisa berubah:

 // Accumulate names into a List
 List<String> list = people.stream().map(Person::getName).collect(Collectors.toList());

 // Accumulate names into a TreeSet
 Set<String> set = people.stream().map(Person::getName).collect(Collectors.toCollection(TreeSet::new));

 // Convert elements to strings and concatenate them, separated by commas
 String joined = things.stream()
                       .map(Object::toString)
                       .collect(Collectors.joining(", "));

 // Compute sum of salaries of employee
 int total = employees.stream()
                      .collect(Collectors.summingInt(Employee::getSalary)));

 // Group employees by department
 Map<Department, List<Employee>> byDept
     = employees.stream()
                .collect(Collectors.groupingBy(Employee::getDepartment));

 // Compute sum of salaries by department
 Map<Department, Integer> totalByDept
     = employees.stream()
                .collect(Collectors.groupingBy(Employee::getDepartment,
                                               Collectors.summingInt(Employee::getSalary)));

 // Partition students into passing and failing
 Map<Boolean, List<Student>> passingFailing =
     students.stream()
             .collect(Collectors.partitioningBy(s -> s.getGrade() >= PASS_THRESHOLD));
Ajay Kumar
sumber
2
Ini tidak menjawab pertanyaan Op, plus tidak ada penjelasan atau deskripsi posting Anda.
Sid
4

Antarmuka Spliterator- adalah fitur inti dari Streaming .

Metode stream()dan parallelStream()standar disajikan dalam Collectionantarmuka. Metode-metode ini menggunakan Spliterator melalui panggilan ke spliterator():

...

default Stream<E> stream() {
    return StreamSupport.stream(spliterator(), false);
}

default Stream<E> parallelStream() {
    return StreamSupport.stream(spliterator(), true);
}

...

Spliterator adalah iterator internal yang memecah aliran menjadi bagian-bagian yang lebih kecil. Bagian-bagian yang lebih kecil ini dapat diproses secara paralel.

Di antara metode lain, ada dua yang paling penting untuk memahami Spliterator:

  • boolean tryAdvance(Consumer<? super T> action) Berbeda dengan Iteratoritu, ia mencoba melakukan operasi dengan elemen berikutnya. Jika operasi berhasil dilakukan, metode kembali true. Jika tidak, mengembalikan false- itu berarti bahwa tidak ada elemen atau ujung aliran.

  • Spliterator<T> trySplit() Metode ini memungkinkan untuk membagi satu set data menjadi banyak set yang lebih kecil sesuai dengan satu atau kriteria lain (ukuran file, jumlah baris, dll).


sumber
"Jika operasi berhasil dilaksanakan .." Anda mungkin harus menulis ulang ini. javadoc tryAdvance lebih jelas: ´Jika elemen yang tersisa ada, melakukan tindakan yang diberikan padanya, mengembalikan true; lain mengembalikan false.´
Piro mengatakan Reinstate Monica