Kedua antarmuka ini hanya mendefinisikan satu metode
public operator fun iterator(): Iterator<T>
Dokumentasi mengatakan Sequence
dimaksudkan untuk menjadi malas. Tapi bukankah Iterable
malas juga (kecuali didukung oleh a Collection
)?
sumber
Kedua antarmuka ini hanya mendefinisikan satu metode
public operator fun iterator(): Iterator<T>
Dokumentasi mengatakan Sequence
dimaksudkan untuk menjadi malas. Tapi bukankah Iterable
malas juga (kecuali didukung oleh a Collection
)?
Perbedaan utama terletak pada semantik dan implementasi fungsi ekstensi stdlib untuk Iterable<T>
dan Sequence<T>
.
Sebab Sequence<T>
, fungsi ekstensi berjalan lambat jika memungkinkan, mirip dengan operasi perantara Java Streams . Misalnya, Sequence<T>.map { ... }
mengembalikan yang lain Sequence<R>
dan tidak benar-benar memproses item hingga operasi terminal seperti toList
atau fold
dipanggil.
Pertimbangkan kode ini:
val seq = sequenceOf(1, 2)
val seqMapped: Sequence<Int> = seq.map { print("$it "); it * it } // intermediate
print("before sum ")
val sum = seqMapped.sum() // terminal
Ini mencetak:
before sum 1 2
Sequence<T>
ditujukan untuk penggunaan yang lambat dan pipelining yang efisien ketika Anda ingin mengurangi pekerjaan yang dilakukan dalam operasi terminal sebanyak mungkin, sama dengan Java Streams. Namun, kemalasan menyebabkan beberapa overhead, yang tidak diinginkan untuk transformasi sederhana yang umum dari koleksi yang lebih kecil dan membuatnya kurang berkinerja.
Secara umum, tidak ada cara yang baik untuk menentukan kapan dibutuhkan, jadi di Kotlin stdlib kemalasan dibuat eksplisit dan diekstraksi ke Sequence<T>
antarmuka untuk menghindari penggunaannya di semua Iterable
secara default.
Karena Iterable<T>
, sebaliknya, fungsi ekstensi dengan semantik operasi perantara bekerja dengan penuh semangat, memproses item segera dan mengembalikan yang lain Iterable
. Misalnya, Iterable<T>.map { ... }
mengembalikan a List<R>
dengan hasil pemetaan di dalamnya.
Kode yang setara untuk Iterable:
val lst = listOf(1, 2)
val lstMapped: List<Int> = lst.map { print("$it "); it * it }
print("before sum ")
val sum = lstMapped.sum()
Ini mencetak:
1 2 before sum
Seperti yang dikatakan di atas, Iterable<T>
tidak malas secara default, dan solusi ini menunjukkan dirinya dengan baik: dalam banyak kasus ia memiliki lokalitas referensi yang baik sehingga memanfaatkan cache CPU, prediksi, prefetching, dll. Sehingga bahkan beberapa penyalinan koleksi masih berfungsi dengan baik cukup dan berkinerja lebih baik dalam kasus sederhana dengan koleksi kecil.
Jika Anda membutuhkan lebih banyak kontrol atas pipeline evaluasi, ada konversi eksplisit ke urutan malas dengan Iterable<T>.asSequence()
fungsi.
Java
(kebanyakanGuava
) penggemarmap
,filter
dan lainnya tidak membawa cukup informasi untuk memutuskan selain dari jenis kumpulan sumber, dan karena sebagian besar koleksi juga dapat diulang, itu bukan penanda yang baik untuk "malas" karena itu biasanya DI MANA SAJA. malas harus eksplisit agar aman.Menyelesaikan jawaban hotkey:
Penting untuk memperhatikan bagaimana Sequence dan Iterable mengulangi seluruh elemen Anda:
Contoh urutan:
list.asSequence().filter { field -> Log.d("Filter", "filter") field.value > 0 }.map { Log.d("Map", "Map") }.forEach { Log.d("Each", "Each") }
Hasil log:
filter - Peta - Masing-masing; filter - Peta - Masing-masing
Contoh Iterable:
list.filter { field -> Log.d("Filter", "filter") field.value > 0 }.map { Log.d("Map", "Map") }.forEach { Log.d("Each", "Each") }
filter - filter - Peta - Peta - Masing - Masing
sumber
Anda dapat menemukan lebih banyak di sini .
sumber