Di Java, perulangan for-each menyederhanakan proses traversal Koleksi atau larik apa pun, tetapi tidak semua pemrogram Java mengetahui beberapa detail perulangan for-each yang akan dijelaskan dalam artikel ini. Tidak seperti istilah lain yang dirilis di Java 5: generik yang dirilis alias, enkapsulasi otomatis, dan parameter variadik, pengembang Java lebih sering menggunakan loop for-each daripada fitur lainnya, tetapi ketika ditanya bagaimana cara kerja loop for-each tingkat lanjut, Atau apa dasar-dasarnya? persyaratan saat menggunakan Koleksi dalam loop for-each, tidak semua orang bisa menjawabnya.
Tutorial dan contoh ini bertujuan untuk mengisi kesenjangan tersebut dengan mempelajari beberapa teka-teki menarik di setiap loop. Oke, mari kita tidak membahas detailnya, mari kita lihat masalah pertama kita dengan loop for-each Java5.
Pertanyaan Loop Lanjutan 1
Pertimbangkan kode berikut yang melintasi agregator atau kelas koleksi yang ditentukan pengguna. Apa yang akan dicetak oleh kode ini, apakah kode tersebut memunculkan pengecualian atau kesalahan kompiler:
Copy kode kodenya sebagai berikut:
tes paket;
/**
* Kelas Java untuk menunjukkan cara kerja setiap loop di Java
*/
kelas publik ForEachTest {
public static void main(String args[]){
CustomCollection<String> myCollection = CustomCollection<String>();
myCollection.add("Jawa");
myCollection.add("Scala");
myCollection.add("Asyik");
//Apa yang akan dilakukan kode ini, bahasa cetak, pengecualian pelemparan, atau kesalahan waktu kompilasi
for(Bahasa string: myCollection){
System.out.println(bahasa);
}
}
}
Di bawah ini adalah kelas CustomCollection kami, yang merupakan kelas generik yang, seperti kelas Koleksi lainnya, bergantung pada ArrayList dan menyediakan metode untuk menambah dan menghapus item dari Koleksi.
Copy kode kodenya sebagai berikut:
tes paket;
Koleksi Kustom kelas publik<T>{
keranjang ArrayList<T> pribadi;
Koleksi Kustom publik(){
ember = Daftar Array baru();
}
ukuran int publik() {
return bucket.size();
}
boolean publik isEmpty() {
kembalikan ember.isEmpty();
}
boolean publik berisi(T o) {
return bucket.contains(o);
}
penambahan boolean publik(T e) {
return bucket.add(e);
}
boolean publik hapus(T o) {
kembalikan ember.hapus(o);
}
}
Menjawab:
Kode di atas tidak dapat dikompilasi karena kelas CustomCollection kami tidak mengimplementasikan antarmuka java.lang.Iterable. Kesalahan waktu kompilasi adalah sebagai berikut:
Copy kode kodenya sebagai berikut:
Pengecualian di thread "utama" java.lang.RuntimeException: Kode sumber tidak dapat dikompilasi - untuk masing-masing tidak berlaku untuk tipe ekspresi
diperlukan: array atau Java.lang.Iterable
ditemukan: tes.CustomCollection
di tes.ForEachTest.main(ForEachTest.java:24)
Fakta menarik untuk dipelajari dari hal ini adalah bahwa perulangan for-each hanya berlaku untuk array Java dan kelas Collection yang mengimplementasikan antarmuka Iterable, dan karena semua kelas Collection bawaan mengimplementasikan antarmuka java.util.Collection dan mewarisi Iterable, ini Detail yang sering diabaikan dapat dilihat pada deklarasi tipe antarmuka Koleksi "antarmuka publik Collection extends Iterable". Jadi untuk mengatasi masalah di atas, Anda dapat memilih untuk membiarkan CustomCollection mengimplementasikan antarmuka Koleksi atau mewarisi AbstrakCollection, yang merupakan implementasi universal default dan menunjukkan cara menggunakan kelas dan antarmuka abstrak secara bersamaan untuk fleksibilitas yang lebih baik. Sekarang mari kita lihat teka-teki kedua dari perulangan for-each:
Kesulitan kedua dengan loop for-each Java:
Contoh kode berikut akan menampilkan ConcurrentModificationException. Di sini kita menggunakan iterator standar dan loop for-each untuk mengulangi ArrayList dan kemudian menghapus elemen. Anda perlu mencari tahu potongan kode mana yang akan memunculkan ConcurrentModificationException dan mengapa? Perhatikan bahwa jawabannya bisa keduanya, tidak keduanya, atau salah satu atau keduanya.
Copy kode kodenya sebagai berikut:
tes paket;
impor java.util.ArrayList;
import java.util.Koleksi;
impor java.util.Iterator;
/**
* Kelas Java untuk mendemonstrasikan cara kerja bagian dalam untuk setiap loop di Java
* @penulis Javin Paul
**/
kelas publik ForEachTest2 {
public static void main(String args[]){
Koleksi<String> daftar = ArrayList baru<String>();
daftar.tambahkan("Android");
daftar.tambahkan("iPhone");
list.add("Windows Mobile");
// Kode mana yang akan memunculkan ConcurrentModificationException, keduanya,
// tidak satupun atau salah satunya
// contoh 1
Iterator<String> itr = daftar.iterator();
while(itr.hasNext()){
String lang = itr.next();
daftar.hapus(lang);
}
//contoh 2
for(Bahasa string: daftar){
list.remove(bahasa);
}
}
}
Sekitar 70% pengembang Java akan mengatakan bahwa blok kode pertama akan memunculkan pengecualian ConcurrentModificationException karena kita tidak menggunakan metode hapus iterator untuk menghapus elemen, tetapi menggunakan metode hapus() ArrayList. Namun, tidak banyak pengembang Java yang mengatakan bahwa masalah yang sama terjadi pada loop for-each karena kami tidak menggunakan iterator di sini. Faktanya, cuplikan kode kedua juga memunculkan ConcurrentModificationException, yang menjadi jelas setelah menyelesaikan kebingungan pertama. Karena perulangan for-each menggunakan Iterator secara internal untuk melintasi Koleksi, perulangan tersebut juga memanggil Iterator.next(), yang memeriksa perubahan (elemen) dan memunculkan ConcurrentModificationException. Anda dapat melihatnya dari keluaran di bawah, yang Anda dapatkan saat menjalankan cuplikan kedua setelah mengomentari cuplikan pertama.
Copy kode kodenya sebagai berikut:
Pengecualian di thread "utama" java.util.ConcurrentModificationException
di java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372)
di java.util.AbstractList$Itr.next(AbstractList.java:343)
di tes.ForEachTest2.main(ForEachTest2.java:34)
Itu saja tentang loop for-each Java5. Kami telah melihat banyak masalah yang dialami pemrogram Java saat menulis kode untuk melakukan iterasi pada kelas Collection, terutama saat melakukan iterasi pada koleksi sambil menghapus elemen pada saat yang bersamaan. Ingatlah untuk selalu menggunakan metode hapus Iterator saat menghapus objek dari Koleksi apa pun (seperti Peta, Set, atau Daftar). Ingat juga bahwa perulangan for-each hanyalah gula sintaksis (gula sintaksis) di atas penggunaan standar kode Iterator standar gula) saja.
Catatan Penerjemah: Gula sintaksis, juga diterjemahkan sebagai tata bahasa berlapis gula, adalah istilah yang ditemukan oleh ilmuwan komputer Inggris Peter J. Landin, yang mengacu pada jenis tata bahasa tertentu yang ditambahkan ke bahasa komputer bahasa, tetapi membuatnya lebih mudah digunakan oleh pemrogram. Secara umum, penggunaan sintaksis gula dapat meningkatkan keterbacaan program, sehingga mengurangi kemungkinan kesalahan kode program.