Soru Java'da iç içe geçmiş döngülerden kurtulmak


Böyle bir iç içe döngü yapısı var:

for (Type type : types) {
    for (Type t : types2) {
         if (some condition) {
             // Do something and break...
             break; // Breaks out of the inner loop
         }
    }
}

Şimdi her iki döngüden nasıl kurtulabilirim. Benzer sorulara baktım, ancak hiçbiri özellikle Java ile ilgili değil. Bu çözümleri uygulayamadım çünkü en çok kullanılan gotolar.

İç döngüyü farklı bir yöntemle koymak istemiyorum.

Güncelleme: Döngüleri yeniden çalıştırmak istemiyorum, kırıldığında döngü bloğunun yürütülmesi bitti.


1542
2018-05-20 09:07


Menşei




Cevaplar:


Diğer cevaplayıcılar gibi kesinlikle tercih etmek iç döngüyü farklı bir yönteme koymak. Bu cevap, sorudaki gereksinimlerin nasıl karşılanabileceğini gösterir.

Kullanabilirsiniz break Dış döngü için bir etiketle. Örneğin:

public class Test {
    public static void main(String[] args) {
        outerloop:
        for (int i=0; i < 5; i++) {
            for (int j=0; j < 5; j++) {
                if (i * j > 6) {
                    System.out.println("Breaking");
                    break outerloop;
                }
                System.out.println(i + " " + j);
            }
        }
        System.out.println("Done");
    }
}

Bu yazdırır:

0 0
0 1
0 2
0 3
0 4
1 0
1 1
1 2
1 3
1 4
2 0
2 1
2 2
2 3
Breaking
Done

2084
2018-05-20 09:11



Bu yapar döngüden sonra doğrudan atlamak. Dene! Evet, etiket döngüden önce gelir, ancak bu, çıkmak istediğiniz yere değil, döngüyü etiketlemesidir. (Ayrıca bir etiket ile devam edebilirsiniz.) - Jon Skeet
Perl ayrıca kendi etiket sistemine de izin vermektedir. Bence çok fazla dil var - Java'da olduğunu pek şaşırtmam. - Evan Carroll
@Evan - bu iddianın doğru olduğunu - doğru olduğunu vaat eden dillerde. Ama Java bu sözü vermez. Bir dil varsayımlarınızla çelişiyorsa, hatalı olan varsayımlarınız olabilir. Bu durumda, ben hala kısmen haklı olduğunuzu düşünüyorum - en az sürpriz olan WRT'nin bu türden hiç kimseyi hiç duymamış (veya unutmuş) break. O zaman bile, istisnalar daha iyi bilinen bir istisnadır (üzgünüm). Ama eğer açık olmasaydı bu konuda hala mutsuz olurdum (küçük döngüler, etiket / break hala yeterince görünür değilse uyarı mesajı). - Steve314
@JWiley. Burada aynı; daha kolay okunur: "vur" geri döndüğünüzde, okumayı durdurabilirsiniz - bakımı daha kolay: geri dönüşten önce bir şeyi tamir ederken, döngü dışında yan etkiler için endişelenmenize gerek yoktur. Hızlı geri dönüş IMHO, genellikle daha kompakt, daha basit bir kod yol açar. - Bruno Grieder
@MuhammadBabar: outerloop bir etikettir. Tam olarak hangi kodu denediğinizi bilmiyorum, fakat cevabımdaki kod derler ve iyi çalışır. - Jon Skeet


Teknik olarak doğru cevap, dış çevrimi etiketlemektir. Pratikte bir iç döngü içinde herhangi bir noktada çıkmak istiyorsanız, kodun bir yönteme (ihtiyaç olduğunda statik bir yöntem) dışsallaştırılması daha iyi olur ve sonra bunu çağırırsınız.

Bu okunabilirlik için para ödeyecek.

Kod şöyle bir şey olur:

private static String search(...) 
{
    for (Type type : types) {
        for (Type t : types2) {
            if (some condition) {
                // Do something and break...
                return search;
            }
        }
    }
    return null; 
}

Kabul edilen cevap için örneği eşleme:

 public class Test {
    public static void main(String[] args) {
        loop();
        System.out.println("Done");
    }

    public static void loop() {
        for (int i = 0; i < 5; i++) {
            for (int j = 0; j < 5; j++) {
                if (i * j > 6) {
                    System.out.println("Breaking");
                    return;
                }
                System.out.println(i + " " + j);
            }
        }
    }
}

369
2017-11-14 18:26



Bazen iç döngü dışında birkaç yerel değişken kullanırsınız, bunların hepsini geçerek rahatsız edici olabilirsiniz. - Haoest
Peki bu çözüm, kabul edilen cevapta olduğu gibi "Bitti" yazdırmayı nasıl gerektirir? - JohnDoe
@JohnDoe diyorsunuz ve sonra System.out.println ("done") yazıyorsunuz; Arama yöntemindeki {} son olarak {} deneyin de bir seçenektir. - Zo72
Bu sanırım daha iyi bir uygulama, ama kırmak yerine devam etmek istiyorsan ne olur? Etiketler, ya eşit derecede iyi (ya da kötü!) Destekliyor, ancak devam etmek için bu mantığı nasıl dönüştüreceğimi bilmiyorum. - Robert Grant
@RobertGrant Mola yerine devam etmek istiyorsanız, dış döngüyü loop yöntemi ve devam etmek için yöntemden dönüş. - Muhd


Döngüler etrafında adlandırılmış bir blok kullanabilirsiniz:

search: {
    for (Type type : types) {
        for (Type t : types2) {
            if (some condition) {
                // Do something and break...
                break search;
            }
        }
    }
}

186
2018-05-20 09:12



Bir etiket kullanmak için yeni bir blok oluşturmanıza gerek yoktur. - Jon Skeet
Hayır, ama niyetini daha açık hale getirir. Kabul edilen cevapla ilgili ilk yorumu görün. - Bombe
aslında bir adlandırılmış blok değil, etiketinden sonra herhangi bir Java ifadesini etiketsiz olarak yazabilirsiniz. name: if(...){...} adlandırılmış durumu yapar? :) - La VloZ Merrill


Ben asla etiket kullanmam. Girmek için kötü bir uygulama gibi görünüyor. İşte ben ne yapardım:

boolean finished = false;
for (int i = 0; i < 5 && !finished; i++) {
    for (int j = 0; j < 5; j++) {
        if (i * j > 6) {
            finished = true;
            break;
        }
    }
}

112
2017-12-07 17:52



Bu olmamalı && !finished yerine || !finished? Ve neden kullanalım break hiç ve kullanımda değil && !finished iç döngü için de mi? - Gandalf
kullanırım break döngüden keyfi olarak çıkabilmek. Bundan sonra kod varsa if engellemek break yürütmeden önce. Ama haklısın &&. Onu düzeltti. - Elle Mundy
güzel çözüm! Tam olarak bir fonksiyona koymanız bazı nedenlerden ötürü tercih edilmediyse, bunu pratikte böyle yapardım. - benroth
İç döngüden sonra bir mantık varsa, idam edilmeye devam edecek ve dış döngü sadece yeni iterasyon başladığında kırılacak ... - Karthik Karuppannan
Bunun neden böyle yapması gerektiğini anlamıyorum. Kodla çalışan kişiler bir dilin tüm özelliklerini kullanabilmelidir. Diğerlerinin anlayabileceği kodları yazmanın önemli olduğunu, ancak bir dil tarafından sağlanan resmi araçların kullanımını kısıtlayarak ve aynı işlevsellik için geçici çözümler bulmanın önemli olduğunu anlıyorum. Yoksa "kötü uygulama" ile başka bir şey mi kastettin? - codepleb


Etiketleri kullanabilirsiniz:

label1: 
for (int i = 0;;) {
    for (int g = 0;;) {
      break label1;
    }
}

79
2018-05-20 09:11



Haksızlık, bu cevap da doğrudur. Ama sadece 55 tane oy .. - WesternGun
Okumak çok daha basit. - dirtysocks45


belki bir fonksiyonla?

public void doSomething(List<Type> types, List<Type> types2){
  for(Type t1 : types){
    for (Type t : types2) {
      if (some condition) {
         //do something and return...
         return;
      }
    }
  }
}

32
2018-05-20 11:43





Geçici bir değişken kullanabilirsiniz:

boolean outerBreak = false;
for (Type type : types) {
   if(outerBreak) break;
    for (Type t : types2) {
         if (some condition) {
             // Do something and break...
             outerBreak = true;
             break; // Breaks out of the inner loop
         }
    }
}

İşlevinize bağlı olarak, iç döngüden de çıkış / çıkış yapabilirsiniz:

for (Type type : types) {
    for (Type t : types2) {
         if (some condition) {
             // Do something and break...
             return;
         }
    }
}

15
2018-05-20 09:11



Bu şekilde darmadağın buldum. - boutta
Sakar ve hata eğilimli IMHO. - orbfish
Döngüden her seferinde ekstra bir koşul kontrolü? Hayır teşekkürler. - ryandenki


Beğenmediyseniz breaks ve gotos, yerine bir "geleneksel" for-in yerine, ekstra abort koşulu ile kullanabilirsiniz:

int a, b;
bool abort = false;
for (a = 0; a < 10 && !abort; a++) {
    for (b = 0; b < 10 && !abort; b++) {
        if (condition) {
            doSomeThing();
            abort = true;
        }
    }
}

10
2017-12-21 22:56





Benzer bir şey yapmam gerekiyordu, ancak bunu yapmak için gelişmiş for döngüsünü kullanmamayı seçtim.

int s = type.size();
for (int i = 0; i < s; i++) {
    for (int j = 0; j < t.size(); j++) {
        if (condition) {
            // do stuff after which you want 
            // to completely break out of both loops
            s = 0; // enables the _main_ loop to terminate
            break;
        }
    }
}

9
2018-02-05 06:04



Durum kırıldıktan sonra tüm öğeleri tekrarlamak için havalı bulmuyorum. Böylece diğer davaya bir mola veriyorum. - boutta
@boutta Bu sonuca nasıl ulaştığınızdan emin değilim. Durum doğru olduğunda, her iki döngü de çıkar. - Swifty McSwifterton
Tamam, ben 'var' manipülasyonu ile parçası alamadım. Ama bu tarz kötü bir tarz buluyorum çünkü s büyüklüğü temsil ediyor. Sonra ddyer'dan açık vars ile cevabı tercih ederim: stackoverflow.com/a/25124317/15108 - boutta
@boutta değiştirebilirsiniz s daha düşük bir değere i veya değiştirmek idaha büyük veya eşit bir değere s, her ikisi de hile yapmalı. Değişim konusunda haklısınız sçünkü daha sonra başka yerlerde kullanılabilir, ama değişiyor i zarar vermez, sadece ilk emin olun for döngülemeye devam etmeyecek. - Zsolti


Döngü testlerine açık bir "çıkış" eklemeyi tercih ederim. Bunu açıklığa kavuşturuyor Döngünün erken sonlanabileceği herhangi bir sıradan okuyucu.

boolean earlyExit = false;
for(int i = 0 ; i < 10 && !earlyExit; i++) {
     for(int j = 0 ; i < 10 && !earlyExit; j++) { earlyExit = true; }
}

5
2017-08-04 17:29