Cara untuk iterate atas daftar di Jawa
Yang agak baru untuk bahasa Jawa I'm mencoba untuk membiasakan diri dengan semua cara (atau setidaknya non-patologis) yang satu mungkin iterate melalui daftar (atau mungkin koleksi lainnya) dan keuntungan atau kerugian dari masing-masing.
Diberikan Daftar<E> daftar
objek, aku tahu dari cara-cara berikut untuk loop melalui semua unsur-unsur:
Dasar untuk loop (tentu saja, ada're setara sementara
/ lakukan saat
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 @amarseillan mencontohkan, bentuk ini adalah pilihan yang buruk
untuk iterasi Daftar ini, karena sebenarnya pelaksanaan
dapatkanmetode ini mungkin tidak seefisien ketika menggunakan
Iterator. Misalnya,
LinkedList` implementasi harus melintasi semua
unsur-unsur sebelumnya saya mendapatkan i-th elemen.
Dalam contoh di atas sana's tidak ada cara untuk Daftar
untuk implementasi
"menghemat tempat" untuk membuat iterasi masa depan yang lebih efisien.
Untuk sebuah ArrayList
itu doesn't benar-benar peduli, karena kompleksitas/biaya masuk
adalah konstanta waktu (O(1)) sedangkan untuk LinkedList
itu berbanding lurus dengan ukuran daftar (O(n)).
Untuk informasi lebih lanjut tentang kompleksitas komputasi dari built-in Koleksi
implementasi, check out ini question.
Ditingkatkan loop (baik menjelaskan dalam hal ini pertanyaan)
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
// ...
}
Fungsional Jawa
list.stream().map(e -> e + 1); // Can apply a transformation function for e
Iterable.forEach, Stream.forEach, ...
(Peta metode dari Jawa 8's Stream API (lihat @i_am_zero's jawaban).)
Di Jawa 8 kelas koleksi yang menerapkan Iterable
(misalnya, semua Daftar ini) sekarang memiliki
forEach` metode, yang dapat digunakan sebagai pengganti untuk loop pernyataan yang ditunjukkan di atas. (Di sini adalah [pertanyaan lain][jawa-8-foreach-perbandingan] yang memberikan perbandingan yang baik.)
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 cara lain yang ada, jika ada?
(BTW, saya minat itu tidak berasal dari keinginan untuk [mengoptimalkan kinerja][iterator-kinerja-pertanyaan]; aku hanya ingin tahu seperti apa bentuk-bentuk yang tersedia bagi saya sebagai pengembang.)
Tiga bentuk perulangan yang hampir identik. Ditingkatkan
untuk
loop:ini, menurut Bahasa Jawa Spesifikasi, identical dalam efek eksplisit menggunakan iterator dengan tradisional
untuk
loop. Dalam kasus ketiga, anda hanya dapat mengubah daftar isi dengan menghapus elemen saat ini, dan kemudian hanya jika anda melakukannya melaluimenghapus
metode iterator itu sendiri. Dengan indeks berbasis iterasi, anda bebas untuk memodifikasi daftar dengan cara apapun. Namun, menambahkan atau menghapus elemen-elemen yang datang sebelum saat ini indeks risiko memiliki loop anda melewatkan unsur-unsur atau pengolahan unsur yang sama beberapa kali, anda perlu menyesuaikan loop indeks dengan benar ketika anda membuat perubahan tersebut.Dalam semua kasus,
elemen
adalah sebuah referensi yang sebenarnya daftar elemen. Tak satu pun dari metode iterasi membuat salinan apa pun dalam daftar. Perubahan keadaan internalelemen
akan selalu terlihat di internal state dari elemen yang sesuai dalam daftar.Pada dasarnya, hanya ada dua cara untuk iterate atas daftar: dengan menggunakan indeks atau dengan menggunakan iterator. Ditingkatkan untuk loop hanya sintaksis shortcut yang diperkenalkan di Jawa 5 untuk menghindari kebosanan secara eksplisit mendefinisikan sebuah iterator. Untuk kedua gaya, anda bisa datang dengan dasarnya sepele variasi menggunakan
untuk
,sementara
ataulakukan saat
blok, tetapi mereka semua mendidih untuk hal yang sama (atau, lebih tepatnya, dua hal).EDIT: Karena @iX3 poin di komentar, anda dapat menggunakan
ListIterator
untuk mengatur arus elemen dari daftar anda iterasi. Anda akan perlu menggunakanklik disini#listIterator()
dan bukanklik disini#iterator()
untuk menginisialisasi variabel loop (yang, jelas, akan menyatakanListIterator
daripadaIterator
).Contoh dari masing-masing jenis yang tercantum dalam pertanyaan:
ListIterationExample.java
Dasar loop tidak dianjurkan karena anda tidak mengetahui implementasi dari daftar.
Jika itu LinkedList, setiap panggilan untuk
akan iterasi daftar, sehingga N^2 kompleksitas waktu.
Sebuah JDK8-gaya iterasi:
Di Jawa 8 kami memiliki beberapa cara untuk iterate atas kelas koleksi.
Menggunakan Iterable forEach
Koleksi yang menerapkan
Iterable
(misalnya semua daftar) sekarang memilikiforEach
metode. Kita dapat menggunakan metode-referensi yang diperkenalkan di Jawa 8.Menggunakan Aliran forEach dan forEachOrdered
Kami juga dapat iterate atas daftar menggunakan Stream:
Kita harus memilih
forEachOrdered
atasforEach
karena perilakuforEach
secara eksplisit nondeterministic mana sebagaiforEachOrdered
melakukan tindakan untuk masing-masing elemen dari aliran ini, dalam rangka menghadapi arus jika arus telah didefinisikan pertemuan order. Jadi forEach tidak menjamin bahwa perintah tersebut akan disimpan.Keuntungan dengan aliran adalah bahwa kami juga dapat membuat penggunaan paralel aliran mana pun yang sesuai. Jika tujuannya adalah hanya untuk mencetak barang-barang tanpa memperhatikan urutan maka kita dapat menggunakan aliran paralel sebagai:
Saya don't tahu apa yang anda anggap patologis, tapi biarkan saya memberikan beberapa alternatif yang bisa anda belum lihat sebelumnya:
Atau versi rekursif:
Juga, rekursif versi klasik
for(int i=0...
:Saya menyebutkan mereka karena anda adalah "agak baru untuk Jawa" dan ini bisa menjadi sesuatu yang menarik.
Anda dapat menggunakan forEach mulai dari Jawa 8:
Di
java 8
anda dapat menggunakanDaftar.forEach()
metodelambda expression
untuk iterate atas daftar.Benar, banyak alternatif yang terdaftar. Cara termudah dan terbersih akan hanya menggunakan ditingkatkan
untuk
pernyataan seperti di bawah ini. TheEkspresi
adalah dari beberapa jenis yang iterable.Misalnya, untuk iterate melalui, Daftar<String> id, kita hanya bisa jadi,
Untuk mundur pencarian anda harus menggunakan yang berikut ini:
Jika anda ingin tahu posisi, menggunakan iterator.previousIndex(). Hal ini juga membantu untuk menulis sebuah loop batin yang membandingkan dua posisi dalam daftar (iterator yang tidak sama).
Anda selalu bisa beralih keluar pertama dan ketiga contoh dengan while loop dan lebih sedikit kode. Ini akan memberikan anda keuntungan yang dapat menggunakan do-while:
Tentu saja, hal semacam ini bisa menyebabkan NullPointerException jika daftar.size() mengembalikan nilai 0, karena selalu mendapat dijalankan setidaknya sekali. Ini bisa diperbaiki dengan pengujian jika elemen nol sebelum menggunakan atribut / metode tho. Namun, itu's jauh lebih sederhana dan lebih mudah digunakan untuk loop