Hari ini kita akan membahas tentang apa itu Iterator di Java dan mengapa itu diperlukan.
Seperti yang mungkin sudah Anda ketahui, Java memiliki antarmuka Koleksi luar biasa yang mengimplementasikan antarmuka Iterator. Izinkan saya segera membuat reservasi: antarmuka iterator tidak sama dengan pola iterator di Java! Dan untuk memperjelasnya, pertama-tama mari kita lihat antarmukanya.
Mari kita bayangkan sejenak bahwa tidak ada iterator di Java. Dalam hal ini, setiap orang harus menyelami koleksi yang paling dalam dan benar-benar memahami apa yang berbeda
Secara harfiah, “Iterator” dapat diterjemahkan sebagai “kekuatan kasar . ” Artinya, ini adalah entitas tertentu yang dapat melakukan iterasi melalui semua elemen dalam koleksi. Selain itu, ini memungkinkan Anda melakukan ini tanpa mempelajari struktur internal dan susunan koleksi. |
ArrayList
dari LinkedList
dan HashSet
dari TreeSet
.
Metode yang harus diterapkan Iterator
boolean hasNext()
— jika masih ada nilai yang tersisa di objek yang dapat diubah (saat ini merupakan Koleksi), metode akan kembali true
, jika tidak ada lagi nilai false
. E next()
— mengembalikan elemen koleksi berikutnya (objek). Jika tidak ada lagi elemen (tidak ada check hasNext()
, dan kami memanggil next()
ketika kami mencapai akhir koleksi), metode ini akan throw NoSuchElementException
. void remove()
- akan menghapus elemen yang terakhir diperoleh oleh next()
. Metodenya bisa membuang:
UnsupportedOperationException
, jika iterator ini tidak mendukung metode iniremove()
(misalnya dalam kasus koleksi hanya-baca)IllegalStateException
, jika metode tersebutnext()
belum dipanggil, atauremove()
sudah dipanggil sejak panggilan terakhirnext()
.
for-each
. Ekstensinya adalah ListIterator. Mari kita lihat metode iterator daftar Java tambahan. Kemungkinan besar Anda mengenal mereka:
void add(E e)
— menyisipkan elemenE
ke dalam ;List
boolean hasPrevious()
— akan kembalitrue
jikaList
ada elemen selama pencarian terbalik;int nextIndex()
— akan mengembalikan indeks elemen berikutnya;E previous()
— akan mengembalikan elemen sheet sebelumnya;int previousIndex()
— akan mengembalikan indeks elemen sebelumnya;void set(E e)
- akan mengganti elemen yang dikembalikan oleh panggilan terakhirnext()
atauprevious()
dengan elemene
.
List
berisi baris-baris ucapan selamat kepada siswa:
List<String> list = new ArrayList<>();
list.add("Hello");
list.add("Обучающимся");
list.add("На");
list.add("JavaRush");
Sekarang kita akan mendapatkan iteratornya dan mencetak semua baris yang ada di konsol:
Iterator iterator = list.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
Sekarang akan ada "hambatan": Koleksi Java, seperti yang mungkin Anda ketahui (dan jika Anda tidak tahu, cari tahu), memperluas antarmuka Iterable
, tetapi ini tidak berarti hanya List
, Set
dan Queue
mendukung iterator. For java Map iterator
juga didukung, tetapi harus dipanggil Map.entrySet()
:
Map<String, Integer> map = new HashMap<>();
Iterator mapIterator = map.entrySet().iterator();
Kemudian metode tersebut next()
akan mengembalikan objek Entry
yang berisi pasangan “kunci” – “nilai”. Maka semuanya sama dengan List
:
while (mapIterator.hasNext()) {
Map.Entry<String, Integer> entry = mapIterator.next();
System.out.println("Key: " + entry.getKey());
System.out.println("Value: " + entry.getValue());
}
Anda berpikir: “Berhenti. Kita berbicara tentang antarmuka, dan judul artikelnya mengatakan “Pola”. Artinya, pola iterator adalah antarmuka Iterator? Atau apakah antarmuka itu sebuah pola? Jika kata ini pertama kali muncul, saya beri referensi: pola adalah pola desain, perilaku tertentu yang harus dipatuhi oleh suatu kelas atau banyak kelas yang saling berhubungan. Sebuah iterator di java dapat diimplementasikan untuk objek apa pun yang struktur internalnya melibatkan iterasi, dan Anda dapat mengubah tanda tangan dari metode yang sedang dibahas. Hal utama ketika mengimplementasikan suatu pola adalah logika yang harus dipatuhi oleh kelas. Antarmuka iterator adalah implementasi pribadi dari pola dengan nama yang sama, diterapkan pada struktur yang sudah jadi ( List, Set, Queue, Map
), dan pada struktur lain, atas kebijaksanaan pemrogram. Dengan memperluas antarmuka Iterator, Anda mengimplementasikan suatu pola, tetapi Anda tidak perlu memperluas antarmuka untuk mengimplementasikan pola tersebut. Analogi sederhananya: semua ikan berenang, tetapi tidak semua yang berenang adalah ikan. Sebagai contoh, saya memutuskan untuk mengambil... kata. Lebih khusus lagi, kata benda. Ini terdiri dari bagian-bagian: awalan, akar, akhiran dan akhir. Untuk bagian dari sebuah kata, kita akan membuat antarmuka WordPart
dan kelas yang memperluasnya: Prefix, Root, Suffix и Ending
:
interface WordPart {
String getWordPart();
}
static class Root implements WordPart {
private String part;
public Root(String part) {
this.part = part;
}
@Override
public String getWordPart() {
return part;
}
}
static class Prefix implements WordPart {
private String part;
public Prefix(String part) {
this.part = part;
}
@Override
public String getWordPart() {
return part;
}
}
static class Suffix implements WordPart {
private String part;
public Suffix(String part) {
this.part = part;
}
@Override
public String getWordPart() {
return part;
}
}
static class Ending implements WordPart {
private String part;
public Ending(String part) {
this.part = part;
}
@Override
public String getWordPart() {
return part;
}
}
Kemudian kelas Word
(kata) akan berisi bagian-bagian, dan sebagai tambahannya kita akan menambahkan bilangan bulat yang mencerminkan jumlah bagian dalam kata tersebut:
public class Word {
private Root root;
private Prefix prefix;
private Suffix suffix;
private Ending ending;
private int partCount;
public Word(Root root, Prefix prefix, Suffix suffix, Ending ending) {
this.root = root;
this.prefix = prefix;
this.suffix = suffix;
this.ending = ending;
this.partCount = 4;
}
public Word(Root root, Prefix prefix, Suffix suffix) {
this.root = root;
this.prefix = prefix;
this.suffix = suffix;
this.partCount = 3;
}
public Word(Root root, Prefix prefix) {
this.root = root;
this.prefix = prefix;
this.partCount = 2;
}
public Word(Root root) {
this.root = root;
this.partCount = 1;
}
public Root getRoot() {
return root;
}
public Prefix getPrefix() {
return prefix;
}
public Suffix getSuffix() {
return suffix;
}
public Ending getEnding() {
return ending;
}
public int getPartCount() {
return partCount;
}
public boolean hasRoot() {
return this.root != null;
}
public boolean hasPrefix() {
return this.prefix != null;
}
public boolean hasSuffix() {
return this.suffix != null;
}
public boolean hasEnding() {
return this.ending != null;
}
Oke, kita memiliki empat konstruktor yang kelebihan beban (untuk mempermudah, anggap saja kita hanya dapat memiliki satu sufiks). Sebuah kata benda tidak bisa terdiri dari satu awalan, jadi untuk konstruktor dengan satu parameter kita akan mengatur root. Sekarang mari kita tulis implementasi pola iterator: WordIterator, dengan mengesampingkan 2 metode: hasNext()
dan next()
:
public class WordIterator implements Iterator<Word.WordPart> {
private Word word;
private int wordPartsCount;
public WordIterator(Word word) {
this.word = word;
this.wordPartsCount = word.getPartCount();
}
@Override
public boolean hasNext() {
if (wordPartsCount == 4) {
return word.hasPrefix() || word.hasRoot() || word.hasSuffix() || word.hasEnding();
} else if (wordPartsCount == 3) {
return word.hasPrefix() || word.hasRoot() || word.hasSuffix();
} else if (wordPartsCount == 2) {
return word.hasPrefix() || word.hasRoot();
} else if (wordPartsCount == 1) {
return word.hasRoot();
}
return false;
}
@Override
public Word.WordPart next() throws NoSuchElementException {
if (wordPartsCount <= 0) {
throw new NoSuchElementException("No more elements in this word!");
}
try {
if (wordPartsCount == 4) {
return word.getEnding();
}
if (wordPartsCount == 3) {
return word.getSuffix();
}
if (wordPartsCount == 2) {
return word.getPrefix();
}
return word.getRoot();
} finally {
wordPartsCount--;
}
}
}
Yang tersisa hanyalah menugaskan iterator ke kelas Word
:
public class Word implements Iterable<Word.WordPart> {
…
@Override
public Iterator<WordPart>iterator() {
return new WordIterator(this);
}
…
}
Sekarang mari kita lakukan analisis morfemik dari kata “rush”:
public class Main {
public static void main(String[] args) {
Word.Root root = new Word.Root("беж");
Word.Prefix prefix = new Word.Prefix("пере");
Word.Suffix suffix = new Word.Suffix("к");
Word.Ending ending = new Word.Ending("a");
Word word = new Word(root, prefix, suffix, ending);
Iterator wordIterator = word.iterator();
while (wordIterator.hasNext()) {
Word.WordPart part = (Word.WordPart) wordIterator.next();
System.out.println(part.getClass() + ": " + part.getWordPart());
}
}
}
Harap dicatat bahwa dalam implementasi pola iterator saya, saya memilih urutan keluaran berikut:
- akhir
- akhiran
- menghibur
- akar
GO TO FULL VERSION