Bu gün Java-da İteratorun nə olduğunu və nə üçün lazım olduğunu danışacağıq .
Yəqin ki, artıq bildiyiniz kimi, Java-nın İterator interfeysini həyata keçirən gözəl Kolleksiya interfeysi var. İcazə verin, dərhal rezervasiya edim: iterator interfeysi Java-dakı iterator nümunəsi ilə qarışdırılmamalıdır! Aydınlaşdırmaq üçün əvvəlcə interfeysə baxaq.
Bir anlığa təsəvvür edək ki, Java-da iterator yoxdur. Bu halda, hər biri kolleksiyaların ən dərinliklərinə girməli və ondan nəyin fərqli olduğunu həqiqətən dərk etməli
Hərfi mənada, "İterator" "kobud qüvvə " kimi tərcümə edilə bilər . Yəni, kolleksiyadakı bütün elementləri təkrarlaya bilən müəyyən bir varlıqdır. Üstəlik, bu, daxili quruluşa və kolleksiyaların təşkilinə diqqət yetirmədən bunu etməyə imkan verir. |
ArrayList
olacaq . LinkedList
HashSet
TreeSet
İteratorun həyata keçirməli olduğu üsullar
boolean hasNext()
— təkrarlana bilən obyektdə (hazırda Kolleksiyada) hələ də dəyərlər qalırsa, true
daha çox dəyər yoxdursa, metod geri qayıdacaq false
. E next()
— kolleksiyanın (obyektin) növbəti elementini qaytarır. Artıq element yoxdursa (heç bir çek yox idi hasNext()
və biz next()
kolleksiyanın sonuna çatdıqda zəng etdik), üsul atacaq NoSuchElementException
. void remove()
- sonuncu tərəfindən əldə edilmiş elementi siləcək next()
. Metod ata bilər:
UnsupportedOperationException
, əgər bu iterator metodu dəstəkləmirsəremove()
(məsələn, yalnız oxunan kolleksiyalar vəziyyətində)IllegalStateException
, əgər metodnext()
hələ çağırılmayıbsa və yaremove()
son zəngdən sonra artıq çağırılıbsanext()
.
for-each
. Onun genişləndirilməsi ListIterator-dur. Əlavə java siyahısı iterator üsullarına baxaq. Çox güman ki, onları tanıyırsınız:
void add(E e)
— element daxilE
edir ;List
boolean hasPrevious()
— əks axtarış zamanı elementlər olarsatrue
qayıdacaq ;List
int nextIndex()
— növbəti elementin indeksini qaytaracaq;E previous()
— əvvəlki vərəq elementini qaytaracaq;int previousIndex()
— əvvəlki elementin indeksini qaytaracaq;void set(E e)
- son zənglə qaytarılan elementinext()
və yaprevious()
elementlə əvəz edəcəke
.
List
Şagirdlərə təbrik sətirlərini ehtiva edən bir yazı yaradaq :
List<String> list = new ArrayList<>();
list.add("Hello");
list.add("Обучающимся");
list.add("На");
list.add("JavaRush");
İndi bunun üçün bir iterator alacağıq və bütün daxil olan sətirləri konsola çap edəcəyik:
Iterator iterator = list.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
İndi bir "darboğaz" olacaq: Java Kolleksiyaları, yəqin ki, bildiyiniz kimi (və bilmirsinizsə, anlayın), interfeysi genişləndirin Iterable
, lakin bu, yalnız o demək deyil ki List
, Set
iteratoru Queue
dəstəkləyir. For java Map iterator
da dəstəklənir, lakin çağırılmalıdır Map.entrySet()
:
Map<String, Integer> map = new HashMap<>();
Iterator mapIterator = map.entrySet().iterator();
Sonra metod “açar”-“dəyər” cütünü ehtiva edən next()
obyekti qaytaracaq . Entry
Sonra hər şey eynidir List
:
while (mapIterator.hasNext()) {
Map.Entry<String, Integer> entry = mapIterator.next();
System.out.println("Key: " + entry.getKey());
System.out.println("Value: " + entry.getValue());
}
Düşünürsən: “Dayan. Söhbət interfeysdən gedir və məqalənin başlığında “Nümunə” deyilir. Yəni, iterator nümunəsi İterator interfeysidir? Yoxsa interfeys nümunədir? Bu söz ilk dəfə görünürsə, mən sizə istinad verirəm: naxış dizayn nümunəsidir, bir sinifin və ya bir-biri ilə əlaqəli bir çox sinifin riayət etməli olduğu müəyyən bir davranışdır. Java-da iterator daxili strukturu təkrarlamağı nəzərdə tutan istənilən obyekt üçün həyata keçirilə bilər və siz müzakirə olunan metodların imzasını dəyişə bilərsiniz. Nümunəni həyata keçirərkən əsas şey sinifin riayət etməli olduğu məntiqdir. İterator interfeysi həm hazır strukturlara ( List, Set, Queue, Map
), həm də proqramçının mülahizəsinə uyğun olaraq digərlərinə tətbiq edilən eyniadlı nümunənin özəl həyata keçirilməsidir. İterator interfeysini genişləndirməklə siz nümunəni həyata keçirirsiniz, lakin nümunəni həyata keçirmək üçün interfeysi genişləndirməyə ehtiyac yoxdur. Sadə bir bənzətmə: bütün balıqlar üzür, amma üzən hər şey balıq deyil. Nümunə olaraq... sözü götürmək qərarına gəldim. Daha dəqiq desək, isim. O, hissələrdən ibarətdir: prefiks, kök, şəkilçi və sonluq. Sözün hissələri üçün biz interfeys WordPart
və onu genişləndirən siniflər yaradacağıq: 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;
}
}
Sonra sinifdə Word
(sözdə) hissələr olacaq və onlara əlavə olaraq sözdəki hissələrin sayını əks etdirən tam ədəd əlavə edəcəyik:
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;
}
Yaxşı, bizdə dörd həddən artıq yüklənmiş konstruktor var (sadəlik üçün fərz edək ki, bizdə yalnız bir şəkilçi ola bilər). İsim bir prefiksdən ibarət ola bilməz, ona görə də bir parametrli konstruktor üçün kök təyin edəcəyik. İndi iterator modelinin tətbiqini yazaq: WordIterator, 2 metodu üstələyən: hasNext()
və 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--;
}
}
}
Qalan yalnız iteratoru sinifə təyin etməkdir Word
:
public class Word implements Iterable<Word.WordPart> {
…
@Override
public Iterator<WordPart>iterator() {
return new WordIterator(this);
}
…
}
İndi isə gəlin “tələs” sözünün morfemik təhlilini aparaq:
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());
}
}
}
Nəzərə alın ki, iterator modelini həyata keçirərkən mən aşağıdakı çıxış sırasını seçdim:
- sona çatır
- şəkilçi
- konsol
- kök
GO TO FULL VERSION