1. Предистория на това How са се появor итераторите
Вече сте запознати с HashSet
. Ако наистина сте го изследвали, освен просто да прочетете урок, тогава трябваше да зададете този въпрос:
Как да покажа списък с всички елементи на HashSet на екрана? В крайна сметка интерфейсът няма get()
и set()
методи!
И HashSet
не е сам в това ограничение. В допълнение към HashSet
, има много други колекции, които не позволяват елементите да бъдат извличани по индекс, тъй като елементите нямат определен ред.
През годините програмистите са изобретor много сложни структури от данни, като например графики и дървета. Или списъци със списъци.
Много контейнери променят реда на своите елементи, когато се добавят нови елементи or се премахват съществуващи елементи. Например списъкът съхранява елементи в определен ред и когато се добави нов елемент, той почти винаги се вмъква в средата на списъка.
И също така получаваме ситуации, в които има контейнер, който съхранява елементи, но не във фиксиран ред.
Сега да кажем, че искаме да копираме всички елементи от такава колекция в масив or списък. Трябва да вземем всички елементи. Ние не се интересуваме от реда, в който итерираме елементите - важното е да не итерирате едни и същи елементи повече от веднъж. Как да направим това?
2. Итератор за колекция
Итераторите бяха предложени като решение на проблема по-горе.
Итераторът е специален обект, свързан с колекция, който помага да се премине през всички елементи на колекцията, без да се повтаря нито един.
Можете да използвате следния code, за да получите итератор за всяка колекция:
Iterator<Type> it = name.iterator();
Къде name
е името на променливата на колекцията, Type
е типът на елементите на колекцията, iterator()
е един от методите на колекцията и it
е името на променливата на итератора.
Итераторният обект има 3 метода:
Метод | Описание |
---|---|
|
Връща следващия елемент в колекцията |
|
Проверява дали има елементи, които все още не са обходени |
|
Премахва текущия елемент от колекцията |
Тези методи са донякъде подобни на класа nextInt)
и hasNextInt()
методите на Scanner.
Методът next()
връща следващия елемент от колекцията, от която сме получor итератора.
Методът hasNext()
проверява дали колекцията има допълнителни елементи, които итераторът все още не е върнал.
Ето How да покажете всички елементи на HashSet
:
Код | Бележки |
---|---|
|
Създайте HashSet обект, който съхранява String елементи. Добавяме поздрави на различни езици към set променливата. Вземете итератор обект за set набора. Докато все още има елементи Вземете следващия елемент Показване на елемента на екрана |
3. For-each
цикъл
Основният недостатък на итератора е, че вашият code става по-тромав от използването на for
цикъл.
За да сравним, нека покажем списък с помощта на for
цикъл и също с помощта на итератор:
Итератор | за цикъл |
---|---|
|
|
Да, много по-добре е да обхождате елементите на цикъл ArrayList
с помощта на цикъл - всичко се оказва по-кратко.
Но създателите на Java отново решиха да ни налеят малко захар. За наш късмет беше синтактична захар .
Те дадоха на Java нов вид цикъл и го нарекоха цикъл for-each
. Ето How изглежда най-общо:
for(Type name:collection)
Къде collection
е името на променливата на колекцията, Type
е типът на елементите в колекцията и name
е името на променлива, която приема следващата стойност от колекцията при всяка итерация на цикъла.
Този вид цикъл итерира през всички елементи на колекция, използвайки имплицитен итератор. Ето How всъщност работи:
За всеки цикъл | Какво вижда компилаторът: Цикъл с итератор |
---|---|
|
|
Когато компилаторът срещне for-each
цикъл във вашия code, той просто го замества с codeа отдясно: добавя извикване за получаване на итератор заедно с всички други липсващи извиквания на метод.
Програмистите обичат for-each
цикъла и почти винаги го използват, когато трябва да повторят всички елементи на колекция.
Дори повторението върху ArrayList
списък с помощта на for-each
цикъл изглежда по-кратко:
За всеки цикъл | за цикъл |
---|---|
|
|
4. Премахване на елемент в for-each
цикъл
Цикълът for-each
има един недостатък: не може да премахва правилно елементи. Ако пишете code по този начин, ще получите грешка.
Код | Забележка |
---|---|
|
Операцията за премахване ще генерира грешка! |
Това е много хубав и разбираем code, но няма да работи.
Не можете да промените колекция, докато я обхождате с итератор.
Има три начина да заобиколите това ограничение.
1. Използвайте различен вид цикъл
When traversing an ArrayList collection
, можете да използвате обикновен цикъл с i
променлива брояч.
Код |
---|
|
Тази опция обаче не е подходяща за HashSet
и HashMap
колекции
2. Използвайте явен итератор
Можете да използвате изрично итератор и да извикате неговия remove()
метод.
Версия, която работи | Версия, която не работи |
---|---|
|
|
Обърнете внимание, че извикваме remove()
метода на обекта на итератора! Итераторът е наясно, че елементът е премахнат и може да се справи със ситуацията правилно.
3. Използвайте копие на сборника
Можете също да създадете копие на колекцията и след това да използвате копието в цикъл for-each
и да изтриете елементи от оригиналната колекция.
Код | Забележка |
---|---|
|
Създаването на копие на колекция е супер лесно. Цикълът използва итератора за копието на колекцията. Елементите се премахват от list колекцията. |
Колекцията се копира доста бързо, тъй като самите елементи не се дублират. Вместо това новата колекция съхранява препратки към елементите, които вече съществуват в старата колекция.
GO TO FULL VERSION