Menjadi agak baru dalam bahasa Jawa saya mencoba membiasakan diri dengan semua cara (atau setidaknya yang non-patologis) yang orang mungkin beralih melalui daftar (atau mungkin koleksi lain) dan kelebihan atau kekurangan masing-masing.
Diberikan List<E> list
objek, saya tahu cara-cara berikut untuk mengulang semua elemen:
Dasar untuk loop (tentu saja, ada yang setara while
/ do while
loop juga)
// Not recommended (see below)!
for (int i = 0; i < list.size(); i++) {
E element = list.get(i);
// 1 - can call methods of element
// 2 - can use 'i' to make index-based calls to methods of list
// ...
}
Catatan: Seperti yang ditunjukkan @amarseillan, formulir ini adalah pilihan yang buruk untuk iterasi List
, karena implementasi sebenarnya dari get
metode ini mungkin tidak seefisien ketika menggunakan Iterator
. Sebagai contoh, LinkedList
implementasi harus melintasi semua elemen sebelum i untuk mendapatkan elemen ke-i.
Dalam contoh di atas tidak ada cara bagi List
implementasi untuk "menyelamatkan tempatnya" untuk membuat iterasi masa depan lebih efisien. Untuk suatu ArrayList
itu tidak terlalu penting, karena kompleksitas / biaya get
adalah waktu yang konstan (O (1)) sedangkan untuk a LinkedList
apakah sebanding dengan ukuran daftar (O (n)).
Untuk informasi lebih lanjut tentang kompleksitas komputasi dari Collections
implementasi bawaan, lihat pertanyaan ini .
Ditingkatkan untuk loop (dijelaskan dengan baik dalam pertanyaan ini )
for (E element : list) {
// 1 - can call methods of element
// ...
}
Iterator
for (Iterator<E> iter = list.iterator(); iter.hasNext(); ) {
E element = iter.next();
// 1 - can call methods of element
// 2 - can use iter.remove() to remove the current element from the list
// ...
}
ListIterator
for (ListIterator<E> iter = list.listIterator(); iter.hasNext(); ) {
E element = iter.next();
// 1 - can call methods of element
// 2 - can use iter.remove() to remove the current element from the list
// 3 - can use iter.add(...) to insert a new element into the list
// between element and iter->next()
// 4 - can use iter.set(...) to replace the current element
// ...
}
Java fungsional
list.stream().map(e -> e + 1); // Can apply a transformation function for e
Iterable.forEach , Stream.forEach , ...
(Metode peta dari Stream API Java 8 (lihat jawaban @ i_am_zero).)
Di Java 8 kumpulan kelas yang mengimplementasikan Iterable
(misalnya, semua List
s) sekarang memiliki forEach
metode, yang dapat digunakan sebagai ganti untuk pernyataan loop ditunjukkan di atas. (Ini adalah pertanyaan lain yang memberikan perbandingan yang bagus.)
Arrays.asList(1,2,3,4).forEach(System.out::println);
// 1 - can call methods of an element
// 2 - would need reference to containing object to remove an item
// (TODO: someone please confirm / deny this)
// 3 - functionally separates iteration from the action
// being performed with each item.
Arrays.asList(1,2,3,4).stream().forEach(System.out::println);
// Same capabilities as above plus potentially greater
// utilization of parallelism
// (caution: consequently, order of execution is not guaranteed,
// see [Stream.forEachOrdered][stream-foreach-ordered] for more
// information about this).
Apa ada cara lain, jika ada?
(BTW, minat saya sama sekali bukan berasal dari keinginan untuk mengoptimalkan kinerja ; Saya hanya ingin tahu bentuk apa yang tersedia bagi saya sebagai pengembang.)
List
antarmuka khusus?Jawaban:
Tiga bentuk perulangan hampir identik.
for
Lingkaran yang disempurnakan :adalah, menurut Spesifikasi Bahasa Jawa , identik dalam efek dengan penggunaan eksplisit dari iterator dengan
for
loop tradisional . Dalam kasus ketiga, Anda hanya dapat mengubah daftar isi dengan menghapus elemen saat ini dan, kemudian, hanya jika Anda melakukannya melaluiremove
metode iterator itu sendiri. Dengan iterasi berbasis indeks, Anda bebas untuk mengubah daftar dengan cara apa pun. Namun, menambahkan atau menghapus elemen yang ada sebelum indeks saat ini berisiko memiliki elemen Anda melewatkan elemen atau memproses elemen yang sama beberapa kali; Anda perlu menyesuaikan indeks loop dengan benar saat Anda melakukan perubahan tersebut.Dalam semua kasus,
element
adalah referensi ke elemen daftar aktual. Tak satu pun dari metode iterasi membuat salinan apa pun dalam daftar. Perubahan pada keadaan internalelement
akan selalu terlihat dalam keadaan internal elemen yang sesuai pada daftar.Pada dasarnya, hanya ada dua cara untuk mengulangi daftar: dengan menggunakan indeks atau dengan menggunakan iterator. Enhanced for loop hanyalah pintasan sintaksis yang diperkenalkan di Java 5 untuk menghindari kebosanan mendefinisikan iterator secara eksplisit. Untuk kedua gaya, Anda dapat membuat variasi yang pada dasarnya sepele menggunakan
for
,while
ataudo while
blok, tetapi semuanya bermuara pada hal yang sama (atau, lebih tepatnya, dua hal).EDIT: Seperti @ iX3 tunjukkan dalam komentar, Anda dapat menggunakan a
ListIterator
untuk mengatur elemen daftar saat ini saat Anda mengulangi. Anda perlu menggunakanList#listIterator()
alih-alihList#iterator()
menginisialisasi variabel loop (yang, jelas, harus dinyatakan sebagaiListIterator
bukanIterator
).sumber
e = iterator.next()
lalu melakukane = somethingElse
hanya mengubah objek apae
yang merujuk daripada mengubah toko yang sebenarnya dari manaiterator.next()
mengambil nilai.e
tidak akan mengubah apa yang ada di daftar; kamu harus meneleponlist.set(index, thing)
. Anda dapat mengubah isi darie
(misalnya,e.setSomething(newValue)
), tetapi untuk perubahan apa elemen disimpan dalam daftar seperti Anda iterasi itu, Anda harus tetap dengan iterasi berbasis indeks.e
saya harus memanggil salah satue
metode karena tugas hanya mengubah pointer (maafkan C saya).Integer
danString
tidak mungkin untuk mengubah konten menggunakanfor-each
atauIterator
metode - harus memanipulasi objek daftar itu sendiri untuk diganti ke elemen. Apakah itu benar?Contoh setiap jenis yang tercantum dalam pertanyaan:
ListIterationExample.java
sumber
Pengulangan dasar tidak disarankan karena Anda tidak tahu implementasi daftar.
Jika itu adalah LinkedList, setiap panggilan ke
akan mengulangi daftar, menghasilkan kompleksitas waktu N ^ 2.
sumber
Iterasi gaya JDK8:
sumber
Di Java 8 kami memiliki banyak cara untuk beralih dari kelas koleksi.
Menggunakan Iterable forEach
Koleksi yang menerapkan
Iterable
(misalnya semua daftar) sekarang memilikiforEach
metode. Kita dapat menggunakan metode-referensi yang diperkenalkan di Java 8.Menggunakan Streams untuk setiap orang dan untuk setiap orang disiapkan
Kami juga dapat mengulangi daftar menggunakan Stream sebagai:
Kita harus memilih
forEachOrdered
lebih dariforEach
karena perilakuforEach
secara eksplisit nondeterministic di mana sebagaiforEachOrdered
melakukan tindakan untuk setiap elemen aliran ini, dalam urutan pertemuan aliran jika aliran memiliki urutan pertemuan yang ditentukan. Jadi forEach tidak menjamin bahwa pesanan akan disimpan.Keuntungan dengan stream adalah kita juga dapat menggunakan stream paralel dimanapun sesuai. Jika tujuannya hanya untuk mencetak barang-barang terlepas dari pesanan maka kita dapat menggunakan aliran paralel sebagai:
sumber
Saya tidak tahu apa yang Anda anggap patologis, tetapi izinkan saya memberikan beberapa alternatif yang belum pernah Anda lihat sebelumnya:
Atau versi rekursifnya:
Juga, versi rekursif klasik
for(int i=0...
:Saya menyebutkannya karena Anda "agak baru ke Jawa" dan ini bisa menarik.
sumber
while(!copyList.isEmpty()){ E e = copyList.remove(0); ... }
. Itu lebih efektif daripada versi pertama;).Anda dapat menggunakan forEach mulai dari Java 8:
sumber
Untuk pencarian mundur Anda harus menggunakan yang berikut:
Jika Anda ingin mengetahui posisi, gunakan iterator.previousIndex (). Ini juga membantu untuk menulis loop batin yang membandingkan dua posisi dalam daftar (iterator tidak sama).
sumber
Benar, banyak alternatif terdaftar. Yang termudah dan terbersih hanya akan menggunakan
for
pernyataan yang disempurnakan seperti di bawah ini. IniExpression
dari beberapa jenis yang dapat diubah.Misalnya, untuk beralih melalui, Daftar <String> id, kita bisa begitu,
sumber
Di
java 8
Anda dapat menggunakanList.forEach()
metode denganlambda expression
untuk mengulangi daftar.sumber
eugene82
jawaban dani_am_zero
jawaban ?Anda selalu dapat mengganti contoh pertama dan ketiga dengan loop sementara dan sedikit kode lagi. Ini memberi Anda keuntungan karena dapat menggunakan do-while:
Tentu saja, hal semacam ini dapat menyebabkan NullPointerException jika list.size () mengembalikan 0, karena selalu dieksekusi setidaknya sekali. Ini dapat diperbaiki dengan menguji apakah elemennya nol sebelum menggunakan atribut / metode tho. Tetap saja, ini jauh lebih sederhana dan lebih mudah digunakan untuk for loop
sumber