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 menggunakanIterator. 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 memilikiforEach` 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.)

Mengomentari pertanyaan (11)
Larutan

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).

Komentar (7)

Contoh dari masing-masing jenis yang tercantum dalam pertanyaan:

ListIterationExample.java

import java.util.*;

public class ListIterationExample {

     public static void main(String []args){
        List numbers = new ArrayList();

        // 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 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 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 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 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 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());
     }
}
Komentar (0)

Dasar loop tidak dianjurkan karena anda tidak mengetahui implementasi dari daftar.

Jika itu LinkedList, setiap panggilan untuk

list.get(i)

akan iterasi daftar, sehingga N^2 kompleksitas waktu.

Komentar (3)

Sebuah JDK8-gaya iterasi:

public class IterationDemo {

    public static void main(String[] args) {
        List list = Arrays.asList(1, 2, 3);
        list.stream().forEach(elem -> System.out.println("element " + elem));
    }
}
Komentar (3)

Di Jawa 8 kami memiliki beberapa cara untuk iterate atas kelas koleksi.

Menggunakan Iterable forEach

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);

Menggunakan Aliran forEach dan forEachOrdered

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);
Komentar (0)

Saya don't tahu apa yang anda anggap patologis, tapi biarkan saya memberikan beberapa alternatif yang bisa anda belum lihat sebelumnya:

List sl= list ;
while( ! sl.empty() ) {
    E element= sl.get(0) ;
    .....
    sl= sl.subList(1,sl.size());
}

Atau versi rekursif:

void visit(List 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 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.

Komentar (5)

Anda dapat menggunakan forEach mulai dari Jawa 8:

 List nameList   = new ArrayList(
            Arrays.asList("USA", "USSR", "UK"));

 nameList.forEach((v) -> System.out.println(v));
Komentar (0)

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 list = new ArrayList();
        list.add("Apple");
        list.add("Orange");
        list.add("Banana");
        list.forEach(
                (name) -> {
                    System.out.println(name);
                }
        );
    }
}
Komentar (3)

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
}
Komentar (1)

Untuk mundur pencarian anda harus menggunakan yang berikut ini:

for (ListIterator 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).

Komentar (0)

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

Komentar (3)