Mengapa Iterator
antarmuka tidak diperluas Iterable
?
The iterator()
Metode hanya bisa kembali this
.
Apakah itu disengaja atau hanya pengawasan desainer Jawa?
Akan lebih mudah untuk menggunakan loop untuk-setiap dengan iterator seperti ini:
for(Object o : someContainer.listSomeObjects()) {
....
}
di mana listSomeObjects()
mengembalikan iterator.
Jawaban:
Karena iterator biasanya menunjuk ke satu instance dalam koleksi. Iterable menyiratkan bahwa seseorang dapat memperoleh iterator dari objek untuk dilintasi elemen-elemennya - dan tidak perlu untuk mengulangi sebuah instance tunggal, yang merupakan apa yang diwakili oleh iterator.
sumber
Sebuah iterator stateful. Idenya adalah bahwa jika Anda menelepon
Iterable.iterator()
dua kali, Anda akan mendapatkan iterator independen - untuk sebagian besar iterables. Itu jelas tidak akan menjadi kasus dalam skenario Anda.Sebagai contoh, saya biasanya dapat menulis:
Itu harus mencetak koleksi dua kali - tetapi dengan skema Anda, loop kedua akan selalu berakhir secara instan.
sumber
iterator
dan menggunakan hasilnya, ia harus mengulangi koleksi - yang tidak akan dilakukan jika objek yang sama telah diulangi pada koleksi. Anda dapat memberikan setiap pelaksanaan yang benar (selain untuk koleksi kosong) di mana iterator yang sama dikembalikan dua kali?iterable
dua kali akan memberi Anda iterator independen.Untuk $ 0,02 saya, saya sepenuhnya setuju bahwa Iterator tidak boleh menerapkan Iterable, tetapi saya pikir peningkatan untuk loop harus menerima baik. Saya pikir seluruh argumen "buat iterator menjadi iterable" muncul sebagai upaya memperbaiki kecacatan dalam bahasa.
Seluruh alasan untuk pengenalan loop yang disempurnakan adalah bahwa hal itu "menghilangkan kerepotan dan kesalahan-kesalahan dari iterator dan variabel indeks ketika iterasi pada koleksi dan array" [ 1 ].
Lalu mengapa argumen yang sama ini tidak berlaku untuk iterator?
Dalam kedua kasus, panggilan ke hasNext () dan next () telah dihapus, dan tidak ada referensi ke iterator di loop dalam. Ya, saya mengerti bahwa Iterables dapat digunakan kembali untuk membuat beberapa iterator, tetapi itu semua terjadi di luar for for loop: di dalam loop hanya ada progres maju satu item pada waktu bersamaan dengan item yang dikembalikan oleh iterator.
Juga, membiarkan ini juga akan membuatnya mudah untuk menggunakan loop for Enumerations, yang, seperti telah ditunjukkan di tempat lain, analog dengan Iterator bukan Iterables.
Jadi jangan membuat Iterator mengimplementasikan Iterable, tetapi perbarui loop for untuk menerima keduanya.
Bersulang,
sumber
for(item : iter) {...}
sintaks, maka iterator akan menimbulkan kesalahan ketika iterator yang sama diulang dua kali. Bayangkan yangIterator
dilewatkan keiterateOver
metode bukanIterable
dalam contoh ini .for (String x : strings) {...}
atauwhile (strings.hasNext()) {...}
: jika Anda mencoba untuk mengulangi iterator dua kali kedua kali tidak akan menghasilkan hasil, jadi saya tidak melihat itu sendiri sebagai argumen yang menentang memperbolehkan sintaks yang ditingkatkan. Jawaban Jon berbeda, karena di sana dia menunjukkan bagaimana membungkus sebuahIterator
dalamIterable
akan menyebabkan masalah, seperti dalam kasus itu Anda akan mengharapkan untuk dapat menggunakannya kembali sebanyak yang Anda suka.Seperti yang ditunjukkan oleh orang lain,
Iterator
danIterable
ada dua hal yang berbeda.Juga,
Iterator
implementasi lebih dulu ditingkatkan untuk loop.Juga sepele untuk mengatasi batasan ini dengan metode adaptor sederhana yang terlihat seperti ini ketika digunakan dengan impor metode statis:
Implementasi sampel:
Di Java 8 mengadaptasi
Iterator
suatuIterable
menjadi lebih sederhana:sumber
for (String s : (Iterable<String>) () -> iterator)
Seperti yang orang lain katakan, Iterable dapat dipanggil beberapa kali, mengembalikan Iterator baru pada setiap panggilan; Iterator hanya digunakan sekali. Jadi mereka saling berhubungan, tetapi melayani tujuan yang berbeda. Namun, frustrasi, metode "kompak untuk" hanya bekerja dengan iterable.
Apa yang akan saya jelaskan di bawah ini adalah salah satu cara untuk mendapatkan yang terbaik dari kedua dunia - mengembalikan sebuah Iterable (untuk sintaksis yang lebih baik) bahkan ketika urutan data yang mendasarinya adalah sekali saja.
Caranya adalah dengan mengembalikan implementasi anterable dari Iterable yang sebenarnya memicu pekerjaan. Jadi alih-alih melakukan pekerjaan yang menghasilkan urutan satu kali dan kemudian mengembalikan Iterator lebih dari itu, Anda mengembalikan Iterable yang, setiap kali diakses, mengulangi pekerjaan. Itu mungkin tampak sia-sia, tetapi sering kali Anda hanya akan memanggil Iterable sekali saja, dan bahkan jika Anda menyebutnya berkali-kali, itu masih memiliki semantik yang masuk akal (tidak seperti pembungkus sederhana yang membuat Iterator "terlihat seperti" yang Iterable, ini akan menang ' t gagal jika digunakan dua kali).
Misalnya, saya memiliki DAO yang menyediakan serangkaian objek dari database, dan saya ingin memberikan akses ke sana melalui iterator (mis. Untuk menghindari membuat semua objek dalam memori jika tidak diperlukan). Sekarang saya hanya bisa mengembalikan iterator, tetapi itu membuat menggunakan nilai yang dikembalikan dalam satu lingkaran jelek. Jadi alih-alih saya membungkus semuanya dalam anon Iterable:
ini kemudian dapat digunakan dalam kode seperti ini:
yang memungkinkan saya menggunakan compact untuk loop sambil tetap menjaga penggunaan memori tambahan.
Pendekatan ini "malas" - pekerjaan tidak dilakukan ketika Iterable diminta, tetapi hanya nanti ketika isinya diulangi - dan Anda perlu menyadari konsekuensi dari itu. Dalam contoh dengan DAO itu berarti mengulangi hasil dalam transaksi basis data.
Jadi ada berbagai peringatan, tetapi ini masih bisa menjadi ungkapan yang berguna dalam banyak kasus.
sumber
returning a fresh Iterator on each call
harus disertai dengan mengapa yaitu untuk mencegah masalah konkurensi ...Hebatnya, belum ada orang lain yang memberikan jawaban ini. Inilah cara Anda dapat "dengan mudah" mengulanginya
Iterator
dengan menggunakan metode Java 8 baruIterator.forEachRemaining()
:Tentu saja, ada solusi "sederhana" yang bekerja dengan loop foreach secara langsung, dengan membungkusnya
Iterator
dalamIterable
lambda:sumber
Iterator
adalah antarmuka yang memungkinkan Anda untuk beralih pada sesuatu. Ini adalah implementasi bergerak melalui koleksi sejenis.Iterable
adalah antarmuka fungsional yang menunjukkan bahwa sesuatu mengandung iterator yang dapat diakses.Di Java8, ini membuat hidup sangat mudah ... Jika Anda memiliki
Iterator
tetapi perlu,Iterable
Anda dapat melakukannya:Ini juga berfungsi di for-loop:
sumber
Saya setuju dengan jawaban yang diterima, tetapi ingin menambahkan penjelasan saya sendiri.
Iterator mewakili keadaan traverse, misalnya, Anda bisa mendapatkan elemen saat ini dari iterator dan bergerak maju ke yang berikutnya.
Iterable mewakili koleksi yang dapat dilintasi, ia dapat mengembalikan sebanyak mungkin iterator yang Anda inginkan, masing-masing mewakili keadaan traversenya sendiri, satu iterator mungkin menunjuk ke elemen pertama, sementara yang lain mungkin menunjuk ke elemen ke-3.
Akan lebih baik jika Java for loop menerima Iterator dan Iterable.
sumber
Untuk menghindari ketergantungan pada
java.util
paketMenurut JSR asli, Lingkaran yang disempurnakan untuk Java ™ Programming Language , antarmuka yang diusulkan:
java.lang.Iterable
java.lang.ReadOnlyIterator
(diusulkan untuk dipasang ke
java.util.Iterator
, tetapi tampaknya ini tidak pernah terjadi)... dirancang untuk menggunakan
java.lang
namespace paket daripadajava.util
.Mengutip JSR:
By the way, yang lama
java.util.Iterable
mendapatkanforEach
metode baru di Java 8+, untuk digunakan dengan sintaks lambda (lewat aConsumer
).Berikut ini sebuah contoh. The
List
antarmuka meluasIterable
antarmuka, sebagai daftar setiap membawaforEach
metode.sumber
Saya juga melihat banyak yang melakukan ini:
Tapi itu tidak benar! Metode ini tidak akan seperti yang Anda inginkan!
Metode
iterator()
ini seharusnya mengembalikan iterator baru mulai dari awal. Jadi orang perlu melakukan sesuatu seperti ini:Pertanyaannya adalah: akankah ada cara untuk membuat kelas abstrak melakukan ini? Sehingga untuk mendapatkan IterableIterator kita hanya perlu mengimplementasikan dua metode next () dan hasNext ()
sumber
Jika Anda datang ke sini untuk mencari solusi, Anda dapat menggunakannya IteratorIterable . (tersedia untuk Java 1.6 ke atas)
Contoh penggunaan (membalikkan Vektor).
cetakan
sumber
Demi kesederhanaan, Iterator dan Iterable adalah dua konsep yang berbeda, Iterable hanyalah sebuah singkatan untuk "Aku bisa mengembalikan Iterator". Saya pikir kode Anda harus:
dengan instanceContainer someof
SomeContainer extends Iterable<Object>
sumber
Sebagai tambahan: Scala memiliki metode toIterable () di Iterator. Lihat scala implisit atau konversi eksplisit dari iterator ke iterable
sumber
Pada catatan terkait, Anda mungkin menemukan adaptor IteratorIterable di Apache Commons Collections4 berguna. Cukup buat instance dari iterator, dan Anda memiliki iterable yang sesuai.
https://commons.apache.org/proper/commons-collections/apidocs/org/apache/commons/collections4/iterators/IteratorIterable.html
ID: org.apache.commons: commons-collections4: 4.0
sumber
Iterator bersifat stateful, mereka memiliki elemen "berikutnya" dan menjadi "habis" begitu iterasi. Untuk melihat di mana masalahnya, jalankan kode berikut, berapa angka yang dicetak?
sumber
Anda dapat mencoba contoh berikut:
sumber