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:
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.
for (E element : list) {
// 1 - can call methods of element
// ...
}
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
// ...
}
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
// ...
}
list.stream().map(e -> e + 1); // Can apply a transformation function for e
(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:
for (E element : list) {
. . .
}
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 melalui menghapus
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 internal elemen
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
atau lakukan 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 menggunakan klik disini#listIterator()
dan bukan klik disini#iterator()
untuk menginisialisasi variabel loop (yang, jelas, akan menyatakan ListIterator
daripada Iterator
).
Contoh dari masing-masing jenis yang tercantum dalam pertanyaan:
import java.util.*;
public class ListIterationExample {
public static void main(String []args){
List<Integer> numbers = new ArrayList<Integer>();
// populates list with initial values
for (Integer i : Arrays.asList(0,1,2,3,4,5,6,7))
numbers.add(i);
printList(numbers); // 0,1,2,3,4,5,6,7
// replaces each element with twice its value
for (int index=0; index < numbers.size(); index++) {
numbers.set(index, numbers.get(index)*2);
}
printList(numbers); // 0,2,4,6,8,10,12,14
// does nothing because list is not being changed
for (Integer number : numbers) {
number++; // number = new Integer(number+1);
}
printList(numbers); // 0,2,4,6,8,10,12,14
// same as above -- just different syntax
for (Iterator<Integer> iter = numbers.iterator(); iter.hasNext(); ) {
Integer number = iter.next();
number++;
}
printList(numbers); // 0,2,4,6,8,10,12,14
// ListIterator<?> provides an "add" method to insert elements
// between the current element and the cursor
for (ListIterator<Integer> iter = numbers.listIterator(); iter.hasNext(); ) {
Integer number = iter.next();
iter.add(number+1); // insert a number right before this
}
printList(numbers); // 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
// Iterator<?> provides a "remove" method to delete elements
// between the current element and the cursor
for (Iterator<Integer> iter = numbers.iterator(); iter.hasNext(); ) {
Integer number = iter.next();
if (number % 2 == 0) // if number is even
iter.remove(); // remove it from the collection
}
printList(numbers); // 1,3,5,7,9,11,13,15
// ListIterator<?> provides a "set" method to replace elements
for (ListIterator<Integer> iter = numbers.listIterator(); iter.hasNext(); ) {
Integer number = iter.next();
iter.set(number/2); // divide each element by 2
}
printList(numbers); // 0,1,2,3,4,5,6,7
}
public static void printList(List<Integer> numbers) {
StringBuilder sb = new StringBuilder();
for (Integer number : numbers) {
sb.append(number);
sb.append(",");
}
sb.deleteCharAt(sb.length()-1); // remove trailing comma
System.out.println(sb.toString());
}
}
Di Jawa 8 kami memiliki beberapa cara untuk iterate atas kelas koleksi.
Koleksi yang menerapkan Iterable
(misalnya semua daftar) sekarang memiliki forEach
metode. Kita dapat menggunakan metode-referensi yang diperkenalkan di Jawa 8.
Arrays.asList(1,2,3,4).forEach(System.out::println);
Kami juga dapat iterate atas daftar menggunakan Stream:
Arrays.asList(1,2,3,4).stream().forEach(System.out::println);
Arrays.asList(1,2,3,4).stream().forEachOrdered(System.out::println);
Kita harus memilih forEachOrdered
atas forEach
karena perilaku forEach
secara eksplisit nondeterministic mana sebagai forEachOrdered
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:
Arrays.asList(1,2,3,4).parallelStream().forEach(System.out::println);
Saya don't tahu apa yang anda anggap patologis, tapi biarkan saya memberikan beberapa alternatif yang bisa anda belum lihat sebelumnya:
List<E> sl= list ;
while( ! sl.empty() ) {
E element= sl.get(0) ;
.....
sl= sl.subList(1,sl.size());
}
Atau versi rekursif:
void visit(List<E> list) {
if( list.isEmpty() ) return;
E element= list.get(0) ;
....
visit(list.subList(1,list.size()));
}
Juga, rekursif versi klasik for(int i=0...
:
void visit(List<E> list,int pos) {
if( pos >= list.size() ) return;
E element= list.get(pos) ;
....
visit(list,pos+1);
}
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:
List<String> nameList = new ArrayList<>(
Arrays.asList("USA", "USSR", "UK"));
nameList.forEach((v) -> System.out.println(v));
Di java 8
anda dapat menggunakan Daftar.forEach()
metode lambda expression
untuk iterate atas daftar.
import java.util.ArrayList;
import java.util.List;
public class TestA {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("Apple");
list.add("Orange");
list.add("Banana");
list.forEach(
(name) -> {
System.out.println(name);
}
);
}
}
Benar, banyak alternatif yang terdaftar. Cara termudah dan terbersih akan hanya menggunakan ditingkatkan untuk
pernyataan seperti di bawah ini. The Ekspresi
adalah dari beberapa jenis yang iterable.
for ( FormalParameter : Expression ) Statement
Misalnya, untuk iterate melalui, Daftar<String> id, kita hanya bisa jadi,
for (String str : ids) {
// Do something
}
Untuk mundur pencarian anda harus menggunakan yang berikut ini:
for (ListIterator<SomeClass> iterator = list.listIterator(list.size()); iterator.hasPrevious();) {
SomeClass item = iterator.previous();
...
item.remove(); // For instance.
}
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:
int i = 0;
do{
E element = list.get(i);
i++;
}
while (i < list.size());
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