JavaRush /Блоги Java /Random-TG /Барои ва барои ҳар як ҳалқа: афсона дар бораи он ки ман ч...
Viacheslav
Сатҳи

Барои ва барои ҳар як ҳалқа: афсона дар бораи он ки ман чӣ гуна такрор кардам, такрор карда шуд, аммо такрор нашуд

Дар гурӯҳ нашр шудааст

Муқаддима

Доиравҳо яке аз сохторҳои асосии забонҳои барномасозӣ мебошанд. Масалан, дар вебсайти Oracle бахши " Дарс: Асосҳои забон " мавҷуд аст, ки дар он ҳалқаҳо дарси алоҳидаи " The for Statement " доранд. Биёед асосҳоро навсозӣ кунем: Давра аз се ифода (изҳод) иборат аст: ибтидосозӣ (оғозсозӣ), шарт (қатъ) ва афзоиш (афзоиш):
Барои ва барои ҳар як ҳалқа: ҳикоя дар бораи он, ки ман чӣ гуна такрор кардам, такрор кардам, аммо такрор накардаам - 1
Ҷолиб он аст, ки ҳамаи онҳо ихтиёрӣ мебошанд, яъне мо метавонем, агар бихоҳем, нависем:
for (;;){
}
Дуруст аст, ки дар ин сурат мо як ҳалқаи беохир ба даст меорем, зеро Мо шарти баромадан аз ҳалқаро муайян намекунем (қатъ). Ифодаи оғозёбӣ танҳо як маротиба пеш аз иҷро шудани тамоми давра иҷро карда мешавад. Ҳамеша бояд дар хотир дошт, ки давра доираи худро дорад. Ин маънои онро дорад, ки ибтидосозӣ , қатъкунӣ , афзоиш ва бадани давр як тағирёбандаҳоро мебинанд. Бо истифода аз қавсҳои ҷингила муайян кардани миқёс ҳамеша осон аст. Ҳама чиз дар дохor қавс берун аз қавс намоён нест, аммо ҳама чизи берун аз қавс дар дохor қавс намоён аст. Оғозсозӣ танҳо як ифода аст. Масалан, ба ҷои оғоз кардани тағирёбанда, шумо метавонед умуман усулеро даъват кунед, ки чизе барнагардонад. Ё танҳо онро гузаред ва пеш аз нуқтаи аввал як холи холӣ гузоред. Ифодаи зерин шарти қатъиро муайян мекунад . То он даме, ки ин дуруст аст , ҳалқа иҷро мешавад. Ва агар false бошад , такрори нав оғоз намешавад. Агар шумо ба расми зер нигаред, мо ҳангоми тартибдиҳӣ хато мегирем ва IDE шикоят хоҳад кард: ифодаи мо дар ҳалқа дастрас нест. Азбаски мо дар давра як итератсия нахоҳем дошт, мо фавран хориҷ мешавем, зеро дурӯғ:
Барои ва барои ҳар як ҳалқа: афсона дар бораи он ки ман чӣ гуна такрор кардам, такрор кардам, аммо такрор накардаам - 2
Ба ибораи изҳороти қатъкунӣ диққат додан лозим аст : он мустақиман муайян мекунад, ки барномаи шумо ҳалқаҳои беохир дорад. Афзоиш соддатарин ифода аст. Он пас аз ҳар як такрори бомуваффақияти давр иҷро карда мешавад. Ва ин ибораро низ партофтан мумкин аст. Барои намуна:
int outerVar = 0;
for (;outerVar < 10;) {
	outerVar += 2;
	System.out.println("Value = " + outerVar);
}
Тавре ки шумо аз мисол мебинед, ҳар як такрори давраро мо ба 2 адад зиёд мекунем, аммо танҳо ба шарте ки арзиш outerVarаз 10 камтар бошад. Илова бар ин, азбаски ифода дар изҳороти афзоиш воқеан танҳо ифода аст, он метавонад ҳама чизро дар бар гирад. Аз ин рӯ, ҳеҷ кас истифодаи коҳишро ба ҷои афзоиш манъ намекунад, яъне. кам кардани арзиш. Шумо бояд ҳамеша навиштани афзоишро назорат кунед. +=аввал афзоиш ва баъд супоришро иҷро мекунад, аммо агар дар мисоли боло акси онро нависем, мо ҳалқаи беохир ба даст меорем, зеро тағирёбанда outerVarҳеҷ гоҳ арзиши тағирёфтаро қабул намекунад: дар ин ҳолат =+пас аз супориш ҳисоб карда мешавад. Воқеан, ин бо афзоиши намоиш низ ҳамин тавр аст ++. Масалан, мо як ҳалқа доштем:
String[] names = {"John","Sara","Jack"};
for (int i = 0; i < names.length; ++i) {
	System.out.println(names[i]);
}
Давра кор кард ва ҳеҷ мушкиле вуҷуд надошт. Аммо баъд марди рефактор омад. Вай афзоишро нафаҳмид ва танҳо чунин кард:
String[] names = {"John","Sara","Jack"};
for (int i = 0; i < names.length;) {
	System.out.println(names[++i]);
}
Агар аломати афзоиш дар пеши арзиш пайдо шавад, ин маънои онро дорад, ки он аввал афзоиш меёбад ва баъд ба ҷои нишондодашуда бармегардад. Дар ин мисол, мо фавран ба истихроҷи унсури индекси 1 аз массив шурӯъ мекунем ва аз аввалро гузаред. Ва он гоҳ дар индекси 3 мо бо хатогии " java.lang.ArrayIndexOutOfBoundsException " дучор мешавем. Тавре ки шумо тахмин кардаед, ин пештар кор мекард, зеро афзоиш пас аз анҷоми итератсия даъват карда мешавад. Ҳангоми интиқоли ин ифода ба такрор, ҳама чиз шикаст. Тавре маълум мешавад, ҳатто дар як ҳалқаи оддӣ шумо метавонед бесарусомонӣ кунед) Агар шумо массив дошта бошед, шояд роҳи осонтари намоиш додани ҳамаи элементҳо вуҷуд дошта бошад?
Барои ва барои ҳар як ҳалқа: афсона дар бораи он ки ман чӣ гуна такрор кардам, такрор кардам, аммо такрор накардаам - 3

Барои ҳар як ҳалқа

Аз Java 1.5 сар карда, таҳиягарони Java ба мо тарҳеро пешниҳод карданд, for each loopки дар сайти Oracle дар дастур бо номи " The For-Each Loop " ё барои versionи 1.5.0 тавсиф шудааст . Умуман, он чунин хоҳад буд:
For и For-Each Loop: сказ о том, How я итерировался, итерировался, да не выитерировался - 4
Шумо метавонед тавсифи ин сохторро дар Мушаххасоти забони Java (JLS) хонед, то боварӣ ҳосил кунед, ки он ҷоду нест. Ин сохтмон дар боби " 14.14.2. Мукаммал барои изҳорот " тавсиф шудааст. Тавре ки шумо мебинед, барои ҳар як ҳалқа бо массивҳо ва онҳое, ки интерфейси java.lang.Iterable -ро амалӣ мекунанд, истифода бурдан мумкин аст . Яъне, агар шумо дар ҳақиқат хоҳед, шумо метавонед интерфейси java.lang.Iterable -ро амалӣ кунед ва барои ҳар як ҳалқа метавонад бо синфи худ истифода шавад. Шумо дарҳол хоҳед гуфт: "Хуб, ин an objectи такроршаванда аст, аммо массив an object нест. Як навъ." Ва шумо хато хоҳед кард, зеро ... Дар Java массивҳо an objectҳои динамикӣ сохта шудаанд. Мушаххасоти забон ба мо чунин мегӯяд: " Дар забони барномасозии Java, массивҳо an objectҳо мебошанд ." Умуман, массивҳо каме ҷодугарии JVM мебошанд, зеро... Чӣ тавр массив дар дохor он сохтор шудааст, маълум нест ва дар ҷое дар дохor мошини виртуалии Java ҷойгир аст. Ҳар касе, ки манфиатдор аст, метавонад ҷавобҳоро дар stackoverflow бихонад: " Синфи массив дар Java чӣ гуна кор мекунад? " Маълум мешавад, ки агар мо массивро истифода набарем, пас мо бояд чизеро истифода барем, ки Iterable -ро амалӣ кунад . Барои намуна:
List<String> names = Arrays.asList("John", "Sara", "Jack");
for (String name : names) {
	System.out.println("Name = " + name);
}
Дар ин ҷо шумо метавонед танҳо дар хотир доред, ки агар мо коллексияҳоро истифода барем ( java.util.Collection ), ба шарофати ин мо маҳз Iterable мегирем . Агар an object дорои синфе бошад, ки Iterable -ро амалӣ мекунад, вай вазифадор аст, ки ҳангоми даъват кардани усули итератор, Итератореро таъмин кунад, ки мундариҷаи он an objectро такрор мекунад. Рамзи дар боло овардашуда, масалан, дорои bytecodeи монанди ин аст (дар IntelliJ Idea шумо метавонед "Намоиш" -> "Байтcodeро нишон диҳед":
For и For-Each Loop: сказ о том, How я итерировался, итерировался, да не выитерировался - 5
Тавре ки шумо мебинед, итератор воқеан истифода мешавад. Агар он барои ҳар як давр намебуд , мо бояд чизе нависем:
List<String> names = Arrays.asList("John", "Sara", "Jack");
for (Iterator i = names.iterator(); /* continue if */ i.hasNext(); /* skip increment */) {
	String name = (String) i.next();
	System.out.println("Name = " + name);
}

Итератор

Тавре ки мо дар боло дидем, интерфейси Iterable мегӯяд, ки барои мисолҳои баъзе an objectҳо шумо метавонед итераторе гиред, ки бо он шумо метавонед мундариҷаро такрор кунед. Боз ҳам метавон гуфт, ки ин Принсипи ягонаи масъулият аз SOLID аст . Худи сохтори додаҳо набояд ҳаракатро пеш барад, аммо он метавонад як чизи лозимаро таъмин кунад. Татбиқи асосии Iterator дар он аст, ки он одатан ҳамчун синфи дохилӣ эълон карда мешавад, ки ба мундариҷаи синфи берунӣ дастрасӣ дорад ва унсури дилхоҳро дар синфи берунӣ таъмин мекунад. Ин аст як мисол аз синф ArrayList, ки чӣ тавр итератор элементро бармегардонад:
public E next() {
            checkForComodification();
            int i = cursor;
            if (i >= size)
                throw new NoSuchElementException();
            Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
            cursor = i + 1;
            return (E) elementData[lastRet = i];
}
Тавре ки мо мебинем, бо ёрии ArrayList.thisитератор ба синфи берунӣ ва тағирёбандаи он дастрасӣ пайдо мекунад elementDataва сипас элементро аз он ҷо бармегардонад. Ҳамин тавр, гирифтани итератор хеле содда аст:
List<String> names = Arrays.asList("John", "Sara", "Jack");
Iterator<String> iterator = names.iterator();
Кори он аз он иборат аст, ки мо метавонем тафтиш кунем, ки оё унсурҳои минбаъда вуҷуд доранд ( усули hasNext ), элементи навбатӣ ( усули навбатӣ ) ва усули хориҷкуниро ба даст оред , ки унсури охирини тавассути next гирифташударо нест мекунад . Усули хориҷ ихтиёрӣ аст ва кафолат дода намешавад, ки амалӣ карда шавад. Дар асл, вақте ки Java таҳаввул меёбад, интерфейсҳо низ таҳаввул мекунанд. Аз ин рӯ, дар Java 8 низ усуле мавҷуд буд forEachRemaining, ки ба шумо имкон медиҳад, ки баъзе амалҳоро дар ҷузъҳои боқимондаи итератор диданнашуда иҷро кунед. Дар бораи итератор ва коллексияҳо чӣ ҷолиб аст? Масалан, синф вуҷуд дорад AbstractList. Ин синфи абстрактист, ки волидайни ArrayListва мебошад LinkedList. Ва ин барои мо аз сабаби чунин соҳа ба монанди modCount ҷолиб аст . Ҳар як тағир додани мундариҷаи рӯйхат тағир меёбад. Пас, ин ба мо чӣ дахл дорад? Ва далели он, ки итератор боварӣ ҳосил мекунад, ки ҳангоми кор коллексияе, ки дар он такрор карда шудааст, тағир намеёбад. Тавре ки шумо фаҳмед, татбиқи итератор барои рӯйхатҳо дар ҳамон ҷо бо modcount , яъне дар синф ҷойгир аст AbstractList. Биёед як мисоли оддиро бубинем:
List<String> names = Arrays.asList("John", "Sara", "Jack");
names = new ArrayList(names);
Iterator<String> iterator = names.iterator();
names.add("modcount++");
System.out.println(iterator.next());
Дар ин ҷо аввалин чизи ҷолиб аст, гарчанде ки дар мавзӯъ нест. Дар асл Arrays.asListяк махсуси худро бармегардонад ArrayList( java.util.Arrays.ArrayList ). Он усулҳои иловакуниро амалӣ намекунад, бинобар ин тағирнопазир аст. Он дар бораи JavaDoc навишта шудааст: fixed-size . Аммо дар асл, он аз андозаи муқарраршуда зиёдтар аст . Он инчунин тағирнопазир аст , яъне тағирнопазир аст; хориҷ кардан низ дар он кор намекунад. Мо низ хато мегирем, зеро... Итераторро сохта, мо дар он modcount ба ёд овардем . Сипас, мо ҳолати коллексияро "берунӣ" иваз кардем (яъне на ба воситаи итератор) ва усули итераторро иҷро кардем. Аз ин рӯ, мо хато мегирем: java.util.ConcurrentModificationException . Барои роҳ надодан ба ин, тағирот ҳангоми итератсия бояд тавассути худи итератор анҷом дода шавад, на тавассути дастрасӣ ба коллексия:
List<String> names = Arrays.asList("John", "Sara", "Jack");
names = new ArrayList(names);
Iterator<String> iterator = names.iterator();
iterator.next();
iterator.remove();
System.out.println(iterator.next());
Тавре ки шумо мефаҳмед, агар iterator.remove()шумо ин корро пештар иҷро накунед iterator.next(), пас аз он сабаб. итератор ба ягон элемент ишора намекунад, он гоҳ мо хато мегирем. Дар мисол, итератор ба унсури Ҷон меравад , онро хориҷ мекунад ва сипас элементи Сараро мегирад . Ва дар ин ҷо ҳама чиз хуб мебуд, аммо бадбахтӣ, боз "нозукиҳо" вуҷуд доранд) java.util.ConcurrentModificationException танҳо вақте рух медиҳад, ки hasNext()он true бармегардад . Яъне, агар шумо элементи охиринро тавассути худи коллексия нест кунед, итератор намеафтад. Барои тафсилоти бештар, беҳтар аст, ки гузоришро дар бораи муаммоҳои Java аз " #ITsubbotnik Section JAVA: Java муаммоҳо " тамошо кунед. Мо чунин сӯҳбати муфассалро бо сабаби оддӣ оғоз кардем, ки маҳз ҳамон нозукиҳо ҳангоми for each loop... Итератори дӯстдоштаи мо дар зери сарпӯш истифода мешавад. Ва ҳамаи ин нозукиҳо дар он ҷо низ татбиқ мешаванд. Ягона чизе, ки мо ба итератор дастрасӣ надорем ва мо наметавонем элементро бехатар хориҷ кунем. Дар омади гап, чунон ки шумо мефаҳмед, давлат дар лаҳзаи эҷоди итератор ба ёд оварда мешавад. Ва ҳазфи бехатар танҳо дар он ҷое, ки онро даъват мекунанд, кор мекунад. Яъне, ин вариант кор намекунад:
Iterator<String> iterator1 = names.iterator();
Iterator<String> iterator2 = names.iterator();
iterator1.next();
iterator1.remove();
System.out.println(iterator2.next());
Зеро барои iterator2 ҳазфкунӣ тавассути iterator1 “берунӣ” буд, яъне он дар ҷое берун иҷро шуда буд ва ӯ дар ин бора чизе намедонад. Дар мавзӯи итераторҳо, ман мехоҳам инро низ қайд кунам. Итератори махсус ва васеъ махсусан барои татбиқи интерфейс сохта шудааст List. Ва ӯро номбар карданд ListIterator. Он ба шумо имкон медиҳад, ки на танҳо ба пеш, балки ба ақиб ҳаракат кунед ва инчунин ба шумо имкон медиҳад, ки индекси элементи қаблӣ ва навбатиро пайдо кунед. Илова бар ин, он ба шумо имкон медиҳад, ки унсури ҷориро иваз кунед ё дар як мавқеъ дар байни мавқеъи ҷории итератор ва дигараш элементи нав гузоред. Тавре ки шумо тахмин кардед, ListIteratorин корро кардан мумкин аст, зеро Listдастрасӣ аз рӯи индекс амалӣ карда мешавад.
For и For-Each Loop: сказ о том, How я итерировался, итерировался, да не выитерировался - 6

Java 8 ва Итератсия

Нашри Java 8 ҳаёти бисёриҳоро осонтар кард. Мо инчунин такрори мундариҷаи an objectҳоро сарфи назар накардем. Барои фаҳмидани он ки ин чӣ гуна кор мекунад, шумо бояд дар бораи ин чанд сухан бигӯед. Java 8 синфи java.util.function.Consumer- ро муаррифӣ кард . Инак як мисол:
Consumer consumer = new Consumer() {
	@Override
	public void accept(Object o) {
		System.out.println(o);
	}
};
Истеъмолкунанда интерфейси функсионалӣ мебошад, ки маънои онро дорад, ки дар дохor интерфейс танҳо 1 усули абстрактии иҷронашуда мавҷуд аст, ки татбиқи ҳатмиро дар ҳамон синфҳо талаб мекунад, ки асбобҳои ин интерфейсро муайян мекунанд. Ин ба шумо имкон медиҳад, ки чунин як чизи ҷодугарро ба монанди ламбда истифода баред. Ин мақола дар бораи он нест, аммо мо бояд фаҳмем, ки чаро мо метавонем онро истифода барем. Ҳамин тавр, бо истифода аз lambdas, Consumer-и дар боло зикршударо метавон чунин навишт: Consumer consumer = (obj) -> System.out.println(obj); Ин маънои онро дорад, ки Java мебинад, ки чизе бо номи obj ба вуруд интиқол дода мешавад ва пас аз он ифодаи баъд аз -> барои ин an object иҷро мешавад. Дар мавриди такрорӣ, мо ҳоло ин корро карда метавонем:
List<String> names = Arrays.asList("John", "Sara", "Jack");
Consumer consumer = (obj) -> System.out.println(obj);
names.forEach(consumer);
Агар шумо ба усули равед forEach, шумо хоҳед дид, ки ҳама чиз девона аст. Ин ҷо дӯстдоштаи мост for-each loop:
default void forEach(Consumer<? super T> action) {
        Objects.requireNonNull(action);
        for (T t : this) {
            action.accept(t);
        }
}
Инчунин бо истифода аз итератор элементро зебо тоза кардан мумкин аст, масалан:
List<String> names = Arrays.asList("John", "Sara", "Jack");
names = new ArrayList(names);
Predicate predicate = (obj) -> obj.equals("John");
names.removeIf(predicate);
Дар ин ҳолат, усули removeIf ҳамчун вуруд на Consumer , балки Predicate мегирад . Он мантиқиро бармегардонад . Дар ин ҳолат, агар предикат " дуруст " гӯяд, он гоҳ элемент хориҷ карда мешавад. Ҷолиб он аст, ки дар ин ҷо ҳам ҳама чиз аён нест)) Хуб, шумо чӣ мехоҳед? Ба одамон барои сохтани муаммоҳо дар конфронс ҷой додан лозим аст. Масалан, биёед рамзи зеринро барои нест кардани ҳама чизе, ки итератор пас аз чанд итератсия дастрас карда метавонад, гирем:
List<String> names = Arrays.asList("John", "Sara", "Jack");
names = new ArrayList(names);
Iterator<String> iterator = names.iterator();
iterator.next(); // Курсор на John
while (iterator.hasNext()) {
    iterator.next(); // Следующий элемент
    iterator.remove(); // Удалor его
}
System.out.println(names);
Хуб, ҳама чиз дар ин ҷо кор мекунад. Аммо мо дар хотир дорем, ки Java 8 дар ниҳоят. Аз ин рӯ, биёед кӯшиш кунем, ки codeро содда кунем:
List<String> names = Arrays.asList("John", "Sara", "Jack");
names = new ArrayList(names);
Iterator<String> iterator = names.iterator();
iterator.next(); // Курсор на John
iterator.forEachRemaining(obj -> iterator.remove());
System.out.println(names);
Оё дар ҳақиқат зеботар шудааст? Аммо, java.lang.IllegalStateException вуҷуд хоҳад дошт . Ва сабабаш... хато дар Java аст. Маълум мешавад, ки он ислоҳ шудааст, аммо дар JDK 9. Дар ин ҷо пайванд ба супориш дар OpenJDK: Iterator.forEachRemaining против. Iterator.remove . Табиист, ки ин аллакай баррасӣ шудааст: Чаро iterator.forEachRemaining элементро дар ламбдаи истеъмолӣ хориҷ намекунад? Хуб, роҳи дигар мустақиман тавассути Stream API аст:
List<String> names = new ArrayList(Arrays.asList("John", "Sara", "Jack"));
Stream<String> stream = names.stream();
stream.forEach(obj -> System.out.println(obj));

хулосахо

Тавре ки мо аз ҳама маводи дар боло овардашуда дидем, ҳалқа for-each loopтанҳо "шакари синтаксисӣ" дар болои итератор аст. Бо вуҷуди ин, он ҳоло дар бисёр ҷойҳо истифода мешавад. Илова бар ин, ҳама гуна маҳсулот бояд бо эҳтиёт истифода шаванд. Масалан, шахси безарар forEachRemainingметавонад сюрпризҳои нохушро пинҳон кунад. Ва ин бори дигар исбот мекунад, ки санҷишҳои воҳид заруранд. Санҷиши хуб метавонад чунин ҳолати истифодаро дар codeи шумо муайян кунад. Он чизе ки шумо метавонед дар ин мавзӯъ тамошо кунед/хонед: #Вячеслав
Шарҳҳо
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION