JavaRush /Java Blog /Random-ID /Rehat kopi #137. For loop atau Foreach - mana yang lebih ...

Rehat kopi #137. For loop atau Foreach - mana yang lebih cepat di Java? 8 Cara Efisien untuk Mengulang Setiap Entri di Peta Java

Dipublikasikan di grup Random-ID

For loop atau Foreach - mana yang lebih cepat di Java?

Sumber: Medium Ketika saya sedang mencari pekerjaan beberapa tahun yang lalu, salah satu pertanyaan yang ditanyakan kepada saya dalam sebuah wawancara adalah apakah kita harus mengulangi penggunaan ArrayList for atau forEach ? Rehat kopi #137.  For loop atau Foreach - mana yang lebih cepat di Java?  8 Cara Efisien untuk Mengulang Setiap Entri di Peta Java - 1Perdebatan tentang perbedaan preferensi antara forEach dan for telah ada sejak lama. Saya mendapat kesan bahwa forEach lebih cepat. Namun pada akhirnya saya menyadari bahwa saya salah. FYI, forEach loop (atau for loop yang ditingkatkan ) yang diperkenalkan di Java 1.5 menghilangkan kekacauan dan kemungkinan kesalahan dengan menyembunyikan variabel iterator atau indeks seluruhnya. Saya percaya satu-satunya perbedaan praktis antara for dan forEach adalah bahwa dalam kasus objek yang diindeks, kami tidak memiliki akses ke indeks.
for(int i = 0; i < mylist.length; i++) {
 if(i < 5) {
 //do something
 } else {
 //do other stuff
 }
}
Namun, kita dapat membuat variabel indeks terpisah bertipe int menggunakan forEach . Misalnya:
int index = -1;
for(int myint : mylist) {
 index++;
 if(index < 5) {
 //do something
 } else {
 //do other stuff
 }
}
Mari kita menulis kelas sederhana yang memiliki metode foreachTest() yang melakukan iterasi melalui daftar menggunakan forEach .
import java.util.List;

public class ForEachTest {
	List<Integer> intList;

    public void foreachTest(){
        for(Integer i : intList){

        }
    }
}
Saat kita mengkompilasi kelas ini, kompiler secara internal mengubah kode menjadi implementasi iterator. Saya mendekompilasi kode yang dikompilasi dengan menjalankan javap -verbose IterateListTest .
public void foreachTest();
   descriptor: ()V
   flags: ACC_PUBLIC
   Code:
     stack=1, locals=3, args_size=1
        0: aload_0
        1: getfield      #19                 // Field intList:Ljava/util/List;
        4: invokeinterface #21,  1           // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator;
        9: astore_2
       10: goto          23
       13: aload_2
       14: invokeinterface #27,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
       19: checkcast     #33                 // class java/lang/Integer
       22: astore_1
       23: aload_2
       24: invokeinterface #35,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
       29: ifne          13
       32: return
     LineNumberTable:
       line 9: 0
       line 12: 32
     LocalVariableTable:
       Start  Length  Slot  Name   Signature
           0      33     0  this   Lcom/greekykhs/springboot/ForEachTest;
     StackMapTable: number_of_entries = 2
       frame_type = 255 /* full_frame */
         offset_delta = 13
         locals = [ class com/greekykhs/springboot/ForEachTest, top, class java/util/Iterator ]
         stack = []
       frame_type = 9 /* same */
Dari bytecode di atas kita melihat:
  1. Perintah getfield digunakan untuk mendapatkan variabel integer.

  2. Panggil List.iterator untuk mendapatkan instance iterator.

  3. Hubungi iterator.hasNext . Jika hasilnya benar, metode iterator.next harus dipanggil .

Mari kita jalankan tes kinerja. Dalam metode utama IterateListTest , saya membuat daftar dan mengulanginya menggunakan for dan forEach loops .
import java.util.ArrayList;
import java.util.List;

public class IterateListTest {
	public static void main(String[] args) {
		List<Integer> mylist = new ArrayList<>();
        for (int i = 0; i < 1000000; i++) {
            mylist.add(i);
        }

        long forLoopStartTime = System.currentTimeMillis();
        for (int i = 0; i < mylist.size(); i++) {mylist.get(i);}

        long forLoopTraversalCost =System.currentTimeMillis()-forLoopStartTime;
        System.out.println("for loop traversal cost for ArrayList= "+ forLoopTraversalCost);

        long forEachStartTime = System.currentTimeMillis();
        for (Integer integer : mylist) {}

        long forEachTraversalCost =System.currentTimeMillis()-forEachStartTime;
        System.out.println("foreach traversal cost for ArrayList= "+ forEachTraversalCost);
	}
}
Dan inilah hasilnya: Rehat kopi #137.  For loop atau Foreach - mana yang lebih cepat di Java?  8 Cara Efisien untuk Mengulang Setiap Entri di Peta Java - 2Seperti yang bisa kita lihat, kinerja perulangan for lebih baik daripada perulangan forEach . Jika Anda menggunakan LinkedList daripada ArrayList , Anda dapat melihat bahwa kinerja forEach lebih baik untuk LinkedList . ArrayList secara internal menggunakan array untuk menyimpan elemen. Karena array adalah wilayah memori yang berdekatan, kompleksitas waktunya adalah O(1). Ini karena data diambil melalui indeks. LinkedList menggunakan daftar tertaut ganda. Saat kita menggunakan perulangan for untuk mengimplementasikan traversal, perulangan tersebut dimulai dari node utama daftar tertaut setiap kali, sehingga kompleksitas waktunya adalah O(n*n).

8 Cara Efisien untuk Mengulang Setiap Entri di Peta Java

Sumber: Medium Minggu lalu, seorang pekerja magang bertanya kepada saya bagaimana cara mengulangi Java Map. Saya menjawab karena sangat sederhana, jawaban atas pertanyaan ini selalu ada di Google. Setelah beberapa waktu, dia mengirimi saya alamat halaman di StackOverflow, dan ternyata banyak sekali orang yang memperhatikan masalah ini. Oleh karena itu, saya memutuskan untuk memikirkan masalah iterasi dan berbagi dengan Anda beberapa cara untuk melakukannya. Rehat kopi #137.  For loop atau Foreach - mana yang lebih cepat di Java?  8 Cara Efisien untuk Mengulang Setiap Entri di Peta Java - 3

1. Menggunakan iterator dan Map.Entry

@Test
public void test1_UsingWhileAndMapEntry(){
    long i = 0;
    Iterator<Map.Entry<Integer, Integer>> it = map.entrySet().iterator();
    while (it.hasNext()) {
        Map.Entry<Integer, Integer> pair = it.next();
        i += pair.getKey() + pair.getValue();
    }
    System.out.println(i);
}

2. Menggunakan foreach dan Map.Entry

@Test
public void test2_UsingForEachAndMapEntry(){
    long i = 0;
    for (Map.Entry<Integer, Integer> pair : map.entrySet()) {
        i += pair.getKey() + pair.getValue();
    }
    System.out.println(i);
}

3. Menggunakan foreach dari Java 8

@Test
public void test3_UsingForEachAndJava8(){
    final long[] i = {0};
    map.forEach((k, v) -> i[0] += k + v);
    System.out.println(i[0]);
}

4. Menggunakan keySet dan foreach

@Test
public void test4_UsingKeySetAndForEach(){
    long i = 0;
    for (Integer key : map.keySet()) {
        i += key + map.get(key);
    }
    System.out.println(i);
}

5. Menggunakan keySet dan iterator

@Test
public void test5_UsingKeySetAndIterator(){
    long i = 0;
    Iterator<Integer> it = map.keySet().iterator();
    while (it.hasNext()) {
        Integer key = it.next();
        i += key + map.get(key);
    }
    System.out.println(i);
}

6. Menggunakan for dan Map.Entry

@Test
public void test6_UsingForAndIterator(){
    long i = 0;
    for (Iterator<Map.Entry<Integer, Integer>> entries = map.entrySet().iterator(); entries.hasNext(); ) {
        Map.Entry<Integer, Integer> entry = entries.next();
        i += entry.getKey() + entry.getValue();
    }
    System.out.println(i);
}

7. Menggunakan API Aliran Java 8

@Test
public void test7_UsingJava8StreamApi(){
    System. out .println(map.entrySet().stream().mapToLong(e -> e.getKey() + e.getValue()).sum());
}

8. Penggunaan Java 8 Stream API secara paralel

@Test
public void test8_UsingJava8StreamApiParallel(){
    System. out .println(map.entrySet().parallelStream().mapToLong(e -> e.getKey() + e.getValue()).sum());
}

Perbandingan masing-masing metode dalam hal kecepatan:

public final static Integer SIZE = 1000000;
public Map<Integer, Integer> map = toMap();
public Map<Integer, Integer> toMap(){
    map = new HashMap<>(SIZE);
    for (int i = 0; i < SIZE; i++) {
        map.put(i, i);
    }
    return map;
}
Kita mendapatkan: Rehat kopi #137.  For loop atau Foreach - mana yang lebih cepat di Java?  8 Cara Efisien untuk Mengulang Setiap Entri di Peta Java - 4Rehat kopi #137.  For loop atau Foreach - mana yang lebih cepat di Java?  8 Cara Efisien untuk Mengulang Setiap Entri di Peta Java - 5Rehat kopi #137.  For loop atau Foreach - mana yang lebih cepat di Java?  8 Cara Efisien untuk Mengulang Setiap Entri di Peta Java - 6

Kesimpulan

Dari perbandingan data, kita mengetahui bahwa metode 6 memakan waktu paling lama dan metode 8 memakan waktu paling banyak ketika angkanya kecil, namun memakan waktu paling sedikit ketika angkanya signifikan karena metode 8 dijalankan secara bersamaan. Menariknya adalah urutan pelaksanaan tes selalu untuk -> while -> foreach/stream dan saya tidak tahu kenapa :(
Komentar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION