JavaRush /Java Blog /Random-TK /For and For-Loop: nädip gaýtalandygym hakda erteki, gaýta...
Viacheslav
Dereje

For and For-Loop: nädip gaýtalandygym hakda erteki, gaýtalandy, ýöne gaýtalanmady

Toparda çap edildi

Giriş

Aýlawlar programmirleme dilleriniň esasy gurluşlaryndan biridir. Mysal üçin, Oracle web sahypasynda “ Sapak: Dil esaslary ” bölümi bar, onda aýlawlarda “ Beýannama üçin ” aýratyn sapak bar. Esasy zatlary täzeläliň: Aýlaw üç aňlatmadan (jümlelerden) ybarat: başlangyç (başlangyç), şert (bes etmek) we artdyrmak (artdyrmak):
Her we her aýlaw üçin: nädip gaýtalandygym, gaýtalandygym, ýöne gaýtalamandygym hakda hekaýa - 1
Gyzykly tarapy, bularyň hemmesi islege bagly, islesek ýazyp bileris:
for (;;){
}
Dogry, bu ýagdaýda tükeniksiz aýlaw alarys, sebäbi Aýlawdan (gutarmak) çykmagyň şertini kesgitlemeýäris. Başlangyç aňlatmasy, ähli aýlaw ýerine ýetirilmänkä diňe bir gezek ýerine ýetirilýär. Bir aýlawyň öz çäginiň bardygyny hemişe ýatdan çykarmaly däldiris. Bu başlangyç , bes etmek , artdyrmak we aýlawly bedeniň şol bir üýtgeýjini görýändigini aňladýar . Bu çäk, egri ýaýlary ulanmak bilen kesgitlemek aňsat. Möjekleriň içindäki hemme zat ýaýyň daşynda görünmeýär, ýöne ýaýyň daşyndaky hemme zat ýaýyň içinde görünýär. Başlamak diňe aňlatma. Mysal üçin, üýtgeýjini başlamagyň ýerine, adatça hiç zady yzyna gaýtarmajak usula jaň edip bilersiňiz. Ora-da birinji nokatdan öň boş ýer goýup, ony taşlaň. Aşakdaky aňlatma bes etmegiň ýagdaýyny kesgitleýär . Çyn bolsa , aýlaw ýerine ýetirilýär. Falsealňyş bolsa , täze gaýtalama başlamaz. Aşakdaky surata seretseňiz, düzülende ýalňyşlyk ýüze çykýar we IDE zeýrener: aýlawdaky aňlatmalarymyz elýeterli däl. Aýlawda ýekeje gezek gaýtalanmajakdygymyz sebäpli derrew çykarys, sebäbi ýalan:
Her we her aýlaw üçin: nädip gaýtaladym, gaýtaladym, ýöne gaýtalamadym erteki - 2
Inationatyryş beýanyndaky aňlatmalara göz aýlamaly : programmaňyzyň tükeniksiz aýlawlarynyň bardygyny gönüden-göni kesgitleýär. Ösüş iň ýönekeý aňlatma. Aýlawyň her gezek üstünlikli gaýtalanmagyndan soň ýerine ýetirilýär. Bu aňlatmany hem atyp bolýar. Mysal üçin:
int outerVar = 0;
for (;outerVar < 10;) {
	outerVar += 2;
	System.out.println("Value = " + outerVar);
}
Mysaldan görnüşi ýaly, aýlawyň her gezek gaýtalanmagy 2 artdyrylar, ýöne bahasy outerVar10-dan az bolsa, artdyrarys, goşmaça beýanyndaky aňlatma aslynda diňe aňlatma bolany üçin islendik zady öz içine alyp biler. Şonuň üçin hiç kim artdyrmagyň ýerine peselmegi ulanmagy gadagan etmeýär. bahasyny peseltmek. Artdyrylyşyň ýazylyşyna hemişe gözegçilik etmeli. +=ilki bilen ýokarlandyrmany ýerine ýetirýär, ýöne ýokardaky mysalda tersini ýazsak, çäksiz aýlaw alarys, sebäbi üýtgeýji outerVarhiç haçan üýtgedilen bahany almaz: bu ýagdaýda =+ýumuşdan soň hasaplanar. .Eri gelende aýtsak, görnüşiň artmagy bilen deňdir ++. Mysal üçin, bizde aýlaw bardy:
String[] names = {"John","Sara","Jack"};
for (int i = 0; i < names.length; ++i) {
	System.out.println(names[i]);
}
Sikl işledi we hiç hili mesele ýokdy. Thenöne soň gaýtadan işleýän adam geldi. Artdyrylyşyna düşünmedi we muny diňe etdi:
String[] names = {"John","Sara","Jack"};
for (int i = 0; i < names.length;) {
	System.out.println(names[++i]);
}
Eger ýokarlandyryş belgisi bahanyň öňünde peýda bolsa, bu ilki köpeljekdigini we soňra görkezilen ýerine gaýdyp geljekdigini aňladýar. Bu mysalda, elementi derrew massiwden 1-nji indeksde çykaryp başlarys. Soň bolsa 3-nji indeksde " java.lang.ArrayIndexOutOfBoundsException " ýalňyşlygy bilen heläk bolarys . Siziň çak edişiňiz ýaly, bu öňem gaýtalama gutarandan soň artma diýilýär. Bu aňlatmany gaýtalama geçirilende hemme zat bozuldy. Görnüşi ýaly, ýönekeý aýlawda-da bulaşdyryp bilersiňiz) Eger massiwiňiz bar bolsa, ähli elementleri görkezmegiň has aňsat usuly barmy?
Her we her aýlaw üçin: nädip gaýtaladym, gaýtaladym, ýöne gaýtalamadym erteki - 3

Her aýlaw üçin

Java 1.5-den başlap, Java döredijiler bize Oracle saýtynda " Her bir aýlawfor each loop " atly gollanmada ýa-da 1.5.0 wersiýasy üçin beýan edilen dizaýny berdiler . Umuman, şeýle bolar:
Her we her aýlaw üçin: nädip gaýtaladym, gaýtaladym, ýöne gaýtalamadym erteki - 4
Bu gurluşyň düşündirişini jadyly däldigine göz ýetirmek üçin Java Dil spesifikasiýasynda (JLS) okap bilersiňiz. Bu gurluşyk " 14.14.2. Beýannama üçin güýçlendirilen " bapda beýan edilýär . Görşüňiz ýaly, her aýlaw üçin massiwler we java.lang.Iterable interfeýsini ulanýanlar ulanylyp bilner . Reallyagny, hakykatdanam isleseňiz, java.lang.Iterable interfeýsini durmuşa geçirip bilersiňiz we her aýlaw üçin synpyňyz bilen ulanylyp bilner. Derrew: "Bolýar, gaýtalanyp boljak zat, ýöne bir massiw obýekt däl. Sort." We ýalňyşarsyňyz, sebäbi ... Java-da massiwler dinamiki taýdan döredilen obýektlerdir. Dil spesifikasiýasy bize muny aýdýar: “ Java programmirleme dilinde massiwler obýektlerdir .” Umuman aýdanyňda, massiwler birneme JVM jadysy, sebäbi ... massiwiň içerki gurluşy näbelli we Java wirtual maşynyň içinde bir ýerde ýerleşýär. Isleg bildirýänler, stackoverflow baradaky jogaplary okap bilerler: " Java-da massiw synpy nähili işleýär? " Görnüşi ýaly, bir massiw ulanmasak, Iterable-i durmuşa geçirýän bir zady ulanmalydyrys . Mysal üçin:
List<String> names = Arrays.asList("John", "Sara", "Jack");
for (String name : names) {
	System.out.println("Name = " + name);
}
Bu ýerde diňe kolleksiýalary ( java.util.Collection ) ulansak , munuň netijesinde takyk Iterable alýandygymyzy ýadyňyzdan çykarmaň . Bir obýektiň “Iterable” -y ýerine ýetirýän synpy bar bolsa, iterator usuly diýlende, şol obýektiň mazmuny boýunça gaýtalanjak Iterator bermäge borçludyr. Mysal üçin ýokardaky kodda şuňa meňzeş bir kod kody bolar (IntelliJ Idea-da "Görmek" -> "Baýtkody görkez" edip bilersiňiz:
Her we her aýlaw üçin: nädip gaýtalandygym, gaýtalandygym, ýöne gaýtalamandygym hakda hekaýa - 5
Görşüňiz ýaly aslynda iterator ulanylýar. Her aýlaw üçin bolmadyk bolsa , şuňa meňzeş bir zat ýazmaly bolardyk:
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);
}

Iterator

Aboveokarda görşümiz ýaly, Iterable interfeýsi käbir obýektleriň mysallary üçin mazmuny gaýtalap boljak iterator alyp bilersiňiz diýýär. Againene-de muny SOLID- den leeke-täk jogapkärçilik ýörelgesi diýip bileris . Maglumat gurluşynyň özi gezelenç sürmeli däl, ýöne zerur bolan birini üpjün edip biler. Iterator-yň esasy durmuşa geçirilmegi , adatça daşarky synpyň mazmunyna girip bilýän we daşarky synpda islenýän elementi üpjün edýän içki synp hökmünde yglan edilmegidir. ArrayListIne, iteratoryň bir elementi nädip yzyna gaýtarýandygynyň synpyndan mysal :
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];
}
Görşümiz ýaly, ArrayList.thisiteratoryň kömegi bilen daşarky synpa we üýtgeýänine girýär elementDatawe soňra bir elementi şol ýerden yzyna berýär. Diýmek, iterator almak gaty ýönekeý:
List<String> names = Arrays.asList("John", "Sara", "Jack");
Iterator<String> iterator = names.iterator();
Onuň işi mundan beýläk elementleriň ( hasNext usuly ) bardygyny ýa-da ýokdugyny barlap, indiki elementi ( indiki usul ) we indiki arkaly alnan soňky elementi aýyrýan aýyrmak usulyny barlap biljekdigimize baglydyr . Aýyrmak usuly islege bagly we ýerine ýetirilmegi kepillendirilmeýär. Aslynda, Java-yň ösmegi bilen interfeýsler hem ösýär. Şonuň üçin Java 8-de iteratoryň girmedik galan elementleri boýunça käbir hereketleri etmäge mümkinçilik berýän usul bar . Iterator we kolleksiýalar näme gyzykly? Mysal üçin, bir synp bar . Bu abstrakt synp we . ModCount ýaly meýdan sebäpli bize gyzykly . Her sanaw sanawyň mazmunyny üýtgedýär. Bu biziň üçin näme möhüm? Iteratoryň iş wagtynda gaýtalanýan kolleksiýasynyň üýtgemejekdigine göz ýetirmegi. Düşünşiňiz ýaly, sanawlar üçin iteratoryň ýerine ýetirilmegi modcount bilen bir ýerde , ýagny synpda ýerleşýär . Simpleönekeý bir meselä seredeliň: forEachRemainingAbstractListArrayListLinkedListAbstractList
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());
Ine, mowzukda bolmasa-da, ilkinji gyzykly zat. Aslynda Arrays.asListöz aýratynlygyny ArrayList( java.util.Arrays.ArrayList ) yzyna berýär. Goşmak usullaryny amala aşyrmaýar, şonuň üçin üýtgedip bolmaýar. JavaDoc-da ýazylýar: kesgitlenen ululykda . Inöne aslynda bu kesgitlenen ululykdan has köp . Şeýle hem üýtgewsiz , ýagny üýtgemez; aýyrmak hem işlemez. Şeýle hem ýalňyşlyk alarys, sebäbi ... Iteratory döredenimizden soň, modkounty ýada saldyk . Soňra kolleksiýanyň ýagdaýyny “daşarky” (ýagny iteratoryň üsti bilen däl) üýtgedip, iterator usulyny ýerine ýetirdik. Şonuň üçin ýalňyşlygy alýarys: java.util.ConcurrentModificationException . Munuň öňüni almak üçin, gaýtalama döwründe üýtgeşme kolleksiýa girmek arkaly däl-de, iteratoryň özi arkaly amala aşyrylmalydyr:
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());
Düşünşiňiz ýaly, öň iterator.remove()etmeseňiz iterator.next(), sebäbi. iterator haýsydyr bir elementi görkezmeýär, şonda ýalňyşlyk alarys. Mysal üçin, iterator Jon elementine geçer , ony aýyrar we Sara elementini alar . Bu ýerde hemme zat gowy bolardy, ýöne şowsuzlyk, ýene-de “nuanslar” bar) java.util.ConcurrentModificationException diňe hakykatahasNext() gaýdyp gelende ýüze çykar . Collectionagny, kolleksiýanyň üsti bilen iň soňky elementi pozsaňyz, iterator ýykylmaz. Has giňişleýin maglumat üçin “ #ITsubbotnik Bölümi JAVA: Java bulgurlary ” -dan Java bulgurlary baradaky hasabaty görmek has gowudyr . Simpleönekeý sebäp bilen şeýle jikme-jik söhbetdeşlige başladyk, şol bir nuanslar ulanylanda ... Iň halanýan iteratorymyz kapotyň aşagynda ulanylýar. Bu nuanslaryň hemmesi şol ýerde-de ulanylýar. Onlyeke-täk zat, iteratoryň ygtyýary bolmaz we elementi arkaýyn aýyryp bilmeris. Wayeri gelende aýtsak, düşünişiňiz ýaly, iterator döredilen pursatynda döwlet ýatda saklanýar. Ygtybarly öçürmek diňe diýilýän ýerde işleýär. .Agny, bu wariant işlemez: for each loop
Iterator<String> iterator1 = names.iterator();
Iterator<String> iterator2 = names.iterator();
iterator1.next();
iterator1.remove();
System.out.println(iterator2.next());
Iterator2 üçin iterator1 arkaly öçürmek “daşarky”, ýagny daşarda bir ýerde ýerine ýetirildi we bu hakda hiç zat bilmeýär. Iteratorlar mowzugynda, muny hem belläsim gelýär. Interfeýs amallary üçin ýörite , giňeldilen iterator ýasaldy List. Olar oňa at dakdylar ListIterator. Diňe öňe däl, eýsem yza hem hereket etmäge mümkinçilik berýär, şeýle hem öňki elementiň we indiki elementiň indeksini tapmaga mümkinçilik berýär. Mundan başga-da, häzirki elementi çalyşmaga ýa-da häzirki iterator ýagdaýy bilen indiki elementiň arasynda täze birini goýmaga mümkinçilik berýär. Siziň çak edişiňiz ýaly, indeks boýunça giriş amala aşyrylandan ListIteratorsoň muny etmäge rugsat berilýär .List
Her we her aýlaw üçin: nädip gaýtalandygym, gaýtalandygym, ýöne gaýtalamandygym hakda erteki - 6

Java 8 we Iteration

Java 8-iň çykmagy köpler üçin durmuşy aňsatlaşdyrdy. Şeýle hem, obýektleriň mazmuny boýunça gaýtalanmagy äsgermezlik etmedik. Munuň nähili işleýändigine düşünmek üçin bu hakda birnäçe söz aýtmaly. Java 8 java.util.function.Consumer synpyny hödürledi . Ine bir mysal:
Consumer consumer = new Consumer() {
	@Override
	public void accept(Object o) {
		System.out.println(o);
	}
};
Sarp ediji funksional interfeýsdir, bu interfeýsiň içinde bu interfeýsiň gurallaryny kesgitleýän şol synplarda hökmany ýerine ýetirilmegini talap edýän diňe 1 ýerine ýetirilmedik abstrakt usulyň bardygyny aňladýar. Bu size lambda ýaly jadyly zady ulanmaga mümkinçilik berýär. Bu makala bu barada däl, ýöne näme üçin ulanyp biljekdigimize düşünmelidiris. Şeýlelik bilen, lambdalary ulanyp, ýokardaky Sarp ediji şeýle ýazylyp bilner: Consumer consumer = (obj) -> System.out.println(obj); Bu, Java obýekt diýilýän zadyň girişe geçiriljekdigini, soň bolsa -> aňlatmasy bu garşylyk üçin ýerine ýetiriljekdigini aňladýar. Gaýtalama barada aýdylanda, indi muny edip bileris:
List<String> names = Arrays.asList("John", "Sara", "Jack");
Consumer consumer = (obj) -> System.out.println(obj);
names.forEach(consumer);
Usula barsaň forEach, hemme zadyň däli bolandygyny görersiň. Iň halanýanlarymyz bar for-each loop:
default void forEach(Consumer<? super T> action) {
        Objects.requireNonNull(action);
        for (T t : this) {
            action.accept(t);
        }
}
Şeýle hem iterator ulanyp, bir elementi owadan aýyrmak mümkindir:
List<String> names = Arrays.asList("John", "Sara", "Jack");
names = new ArrayList(names);
Predicate predicate = (obj) -> obj.equals("John");
names.removeIf(predicate);
Bu ýagdaýda removeIf usuly Sarp ediji däl-de , Predicate hökmünde kabul edilýär . Boolean _ _ Bu ýagdaýda, predikat " dogry " diýse, element aýrylar. Bu ýerde hemme zadyň aýdyň däldigi gyzykly)) Näme isleýärsiňiz? Maslahatda adamlara bulgur döretmek üçin ýer berilmeli. Mysal üçin, iteratoryň birnäçe gaýtalandan soň ýetip biljek ähli zadyny pozmak üçin aşakdaky kody alalyň:
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);
Bolýar, hemme zat şu ýerde işleýär. Javaöne ýadymyzdan çykarma, Java 8. Şonuň üçin kody ýönekeýleşdirmäge synanyşalyň:
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);
Aslynda has owadan boldumy? Şeýle-de bolsa, java.lang.IllegalStateException bolar . Munuň sebäbi bolsa ... Java-da bir näsazlyk. Görnüşi ýaly, düzedildi, ýöne JDK 9-da. Ine, OpenJDK-daky meselä baglanyşyk: Iterator.forEachRemaining vs. Iterator.remove . Elbetde, bu eýýäm ara alnyp maslahatlaşyldy: Näme üçin iterator.forEachRemaining Consumer lambda elementini aýyrmaýar? Başga bir ýol gönüden-göni “Stream API” -iň üsti bilen:
List<String> names = new ArrayList(Arrays.asList("John", "Sara", "Jack"));
Stream<String> stream = names.stream();
stream.forEach(obj -> System.out.println(obj));

Netijeler

Aboveokardaky ähli materiallardan görşümiz ýaly, aýlaw for-each loopdiňe iteratoryň üstünde “sintaktik şeker”. Şeýle-de bolsa, indi köp ýerlerde ulanylýar. Mundan başga-da, islendik önüm seresaplylyk bilen ulanylmalydyr. Mysal üçin, zyýansyz adam forEachRemainingýakymsyz garaşylmadyk zatlary gizläp biler. Bu bolsa birlik synaglarynyň zerurdygyny ýene bir gezek subut etdi. Gowy synag, koduňyzda şeýle ulanylyş ýagdaýyny kesgitläp biler. Mowzukda tomaşa edip / okap boljak zatlaryňyz: # Wiaçeslaw
Teswirler
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION