Ist es eine schlechte Praxis, break zu verwenden, um eine Schleife in Java zu beenden? [geschlossen]


79

Ich habe mich gefragt, ob es eine "schlechte Praxis" ist, eine breakAnweisung zum Verlassen einer Schleife zu verwenden, anstatt die Schleifenbedingung zu erfüllen.

Ich habe nicht genug Einblick in Java und die JVM, um zu wissen, wie eine Schleife behandelt wird, und habe mich gefragt, ob ich dabei etwas Kritisches übersehen habe.

Der Fokus dieser Frage: Gibt es einen bestimmten Leistungsaufwand?


13
Ich glaube nicht, dass es eine schlechte Praxis ist, da "Pause" nur dafür gedacht ist
Android Killer

19
Was wäre eine schlechte Praxis, wäre 1 Million Mal zu schleifen, selbst wenn Sie nach 5 Iterationen beendet haben könnten ...
Assylias

2
Ich persönlich denke, es hängt von der Situation ab. Manchmal kann die Verwendung von break die Lesbarkeit von Code
verbessern

2
Dies wird als schlechte Vorgehensweise angesehen, da dies zu vielen unerwünschten Situationen führen kann, z. B. zum Beenden der Schleife / Methode, nachdem der Stream erstellt und nicht geschlossen wurde. Aber wenn Sie es vorsichtig verwenden, ist es in Ordnung.
Pshemo

3
Grundsätzlich können Sie jeden breakdurch einen ifum den gesamten Rest des Codes ersetzen . So wird es in einigen anderen Sprachen gemacht, die faschistisch dem Paradigma der "strukturierten Programmierung" folgen. Der Code sieht schrecklich aus.
Marko Topolnik

Antworten:


134

Guter Herr, nein. Manchmal besteht die Möglichkeit, dass in der Schleife etwas auftritt, das die Gesamtanforderung erfüllt, ohne die logische Schleifenbedingung zu erfüllen. In diesem Fall breakwird verwendet, um zu verhindern, dass Sie sinnlos um eine Schleife fahren.

Beispiel

String item;

for(int x = 0; x < 10; x++)
{
    // Linear search.
    if(array[x].equals("Item I am looking for"))
    {
       //you've found the item. Let's stop.
       item = array[x];
       break; 
    }
}

Was macht in diesem Beispiel mehr Sinn. Setzen Sie die Schleife jedes Mal auf 10 fort, auch nachdem Sie sie gefunden haben, oder wiederholen Sie die Schleife, bis Sie den Gegenstand gefunden haben und anhalten? Oder um es in reale Begriffe zu fassen; Wenn Sie Ihre Schlüssel finden, suchen Sie weiter?

Als Antwort auf einen Kommentar bearbeiten

Warum setzen nicht xauf 11die Schleife zu brechen? Es hat keinen Sinn. Wir haben break! Wenn Ihr Code nicht davon ausgeht, dass er xdefinitiv größer ist als 10später (und wahrscheinlich auch nicht), können Sie ihn nur verwenden break.

Der Vollständigkeit halber bearbeiten

Es gibt definitiv andere Möglichkeiten zu simulieren break. Fügen Sie beispielsweise Ihrer Beendigungsbedingung in Ihrer Schleife zusätzliche Logik hinzu. Zu sagen, dass es entweder sinnlos ist oder verwendet wird, breakist nicht fair. Wie bereits erwähnt, kann eine while-Schleife häufig ähnliche Funktionen erzielen. Folgen Sie beispielsweise dem obigen Beispiel.

while(x < 10 && item == null)
{
    if(array[x].equals("Item I am looking for"))
    {
        item = array[x];
    }

    x++;
}

Mit breakeinfach bedeutet, dass Sie diese Funktionalität mit einer forSchleife erreichen können. Dies bedeutet auch, dass Sie nicht immer Bedingungen in Ihre Beendigungslogik einfügen müssen, wenn Sie möchten, dass sich die Schleife anders verhält. Zum Beispiel.

for(int x = 0; x < 10; x++)
{
   if(array[x].equals("Something that will make me want to cancel"))
   {
       break;
   }
   else if(array[x].equals("Something else that will make me want to cancel"))
   {
       break;
   }
   else if(array[x].equals("This is what I want"))
   {
       item = array[x];
   }
}

Anstatt einer while loopmit einer Kündigungsbedingung, die so aussieht:

while(x < 10 && !array[x].equals("Something that will make me want to cancel") && 
                !array[x].equals("Something else that will make me want to cancel"))

Das OP fragte auch nach etwas ähnlichem wie das Setzen von x auf 1000, um die Schleife zu brechen /
nanofarad

5
Was ist mit einer while-Schleife anstelle einer Pause? Dann sind alle Bedingungen für den Abschluss der Schleife direkt am Anfang der Schleife. while(x < 10 && item == null)Wenn Sie Lust haben, verwenden Sie einen Iterator.
Freiheit

@Freiheit: du kannst es benutzen oder sogar verbessern. Aber ich denke, ein Beispiel dafür Chrisist das Verständnis von OP.
Nandkumar Tekale

1
@hexafraction: Was ist, wenn ich den xIndex im Code unterhalb der Schleife verwenden möchte ? zBfound string at index x
Nandkumar Tekale

@NandkumarTekale Dann müssen Sie es draußen deklarieren und mit intakter Schleife aus der Schleife ausbrechen.
Nanofarad

18

Die Verwendung break, wie praktisch jede andere Sprachfunktion, kann in einem bestimmten Kontext, in dem Sie sie eindeutig missbrauchen, eine schlechte Praxis sein. Einige sehr wichtige Redewendungen können jedoch nicht ohne sie codiert werden oder würden zumindest zu einem weitaus weniger lesbaren Code führen. In diesen Fällen breakist der Weg zu gehen.

Mit anderen Worten, hören Sie nicht auf pauschale, uneingeschränkte Ratschläge - über breakoder irgendetwas anderes. Es ist nicht ein einziges Mal, dass ich Code völlig abgemagert gesehen habe, nur um eine "gute Praxis" buchstäblich durchzusetzen.

In Bezug auf Ihre Bedenken hinsichtlich des Leistungsaufwands gibt es absolut keine. Auf Bytecode-Ebene gibt es sowieso keine expliziten Schleifenkonstrukte: Die gesamte Flusssteuerung wird in Form von bedingten Sprüngen implementiert.


6

Das JLS gibt an, dass eine Unterbrechung eine abnormale Beendigung einer Schleife ist. Nur weil es als abnormal angesehen wird, bedeutet dies nicht, dass es nicht in vielen verschiedenen Codebeispielen, Projekten, Produkten, Space Shuttles usw. verwendet wird. Die JVM-Spezifikation gibt weder das Vorhandensein noch das Fehlen eines Leistungsverlusts an, obwohl dies der Fall ist Die Ausführung des Löschcodes wird nach der Schleife fortgesetzt.

Die Lesbarkeit des Codes kann jedoch durch ungerade Unterbrechungen beeinträchtigt werden. Wenn Sie eine Unterbrechung in einer komplexen if-Anweisung festhalten, die von Nebenwirkungen und seltsamem Bereinigungscode umgeben ist, möglicherweise mit einer mehrstufigen Unterbrechung mit einem Label (oder schlimmer noch mit einer Reihe seltsamer Beendigungsbedingungen nacheinander), wird dies nicht der Fall sein für jeden leicht lesbar sein.

Wenn Sie Ihre Schleife unterbrechen möchten, indem Sie die Iterationsvariable außerhalb des Iterationsbereichs erzwingen oder auf andere Weise eine nicht unbedingt direkte Methode zum Beenden einführen, ist sie weniger lesbar als break.

Es ist jedoch fast immer eine schlechte Praxis , zusätzliche Zeiten auf leere Weise zu wiederholen, da zusätzliche Iterationen erforderlich sind und möglicherweise unklar sind.


5

Meiner Meinung nach sollte eine ForSchleife verwendet werden, wenn eine feste Anzahl von Iterationen durchgeführt wird und diese nicht gestoppt werden, bevor jede Iteration abgeschlossen ist. In dem anderen Fall, in dem Sie früher beenden möchten, bevorzuge ich die Verwendung einer WhileSchleife. Selbst wenn Sie diese beiden kleinen Wörter lesen, scheint es logischer. Einige Beispiele:

for (int i=0;i<10;i++) {
    System.out.println(i);
}

Wenn ich diesen Code schnell lese, weiß ich sicher, dass er 10 Zeilen ausdruckt und dann weitergeht.

for (int i=0;i<10;i++) {
    if (someCondition) break;
    System.out.println(i);
}

Dieser ist mir schon weniger klar. Warum würden Sie zuerst angeben, dass Sie 10 Iterationen durchführen werden, aber dann innerhalb der Schleife einige zusätzliche Bedingungen hinzufügen, um früher zu stoppen?

Ich bevorzuge das vorherige Beispiel, das auf diese Weise geschrieben wurde (auch wenn es etwas ausführlicher ist, aber nur mit 1 Zeile mehr):

int i=0;
while (i<10 && !someCondition) {
    System.out.println(i);
    i++;
}

Jeder, der diesen Code liest, wird sofort feststellen, dass es eine zusätzliche Bedingung gibt, die die Schleife möglicherweise früher beendet.

Natürlich können Sie in sehr kleinen Schleifen immer diskutieren, dass jeder Programmierer die break-Anweisung bemerkt. Aber ich kann aus eigener Erfahrung sagen, dass in größeren Schleifen diese Pausen überwacht werden können. (Und das bringt uns zu einem anderen Thema, um Code in kleinere Teile aufzuteilen.)


2
Dies berücksichtigt nicht die Situation, in der eine Bedingung WÄHREND der for- oder while-Schleife erreicht wird. Wenn die for / while-Schleife eine Bedingung auslöst (oder möglicherweise etwas in einem anderen Thread ausgeführt wird), müssen Sie möglicherweise vorzeitig abbrechen. Die von Ihnen geschriebene while-Schleife setzt voraus, dass Sie die Bedingung nur zu Beginn einer Iteration überprüfen müssen.
Doc

Dem stimme ich voll und ganz zu. Wenn Sie eine for-Schleife haben, ist beabsichtigt, dass sich die Logik für die Initialisierung, die Bedingung und das Inkrement an einer Stelle befinden. Dies erspart es, hier und überall nachsehen zu müssen, um genau zu finden, was möglicherweise vor sich geht. Wenn Sie nicht wissen, wie oft Sie eine Schleife durchführen möchten, führen Sie eine Schleife "while" durch, daher sollte es sich um eine while-Schleife handeln. Wenn Sie bis zu etwas schleifen, sollte es eine Weile dauern. Ich behaupte überhaupt nicht, dass Pausen eine schlechte Praxis sind, aber es gibt eine Zeit und einen Ort für sie.
ThePerson

4

Die Verwendung von Break-In-Schleifen kann durchaus legitim sein und sogar die einzige Möglichkeit sein, einige Probleme zu lösen.

Der schlechte Ruf beruht jedoch auf der Tatsache, dass neue Programmierer ihn normalerweise missbrauchen, was zu verwirrendem Code führt, insbesondere durch die Verwendung von break, um die Schleife unter Bedingungen zu stoppen, die möglicherweise überhaupt in die Schleifenbedingungsanweisung geschrieben wurden.


Ich sehe das zu oft. Ich würge jedes Mal, wenn ein See-Code Schleifenvariablen initialisiert, die Schleife mit öffnet while(true)und dann breakunter bestimmten Bedingungen s.
John

@ John, während manchmal missbraucht, ist daran nichts auszusetzen, einige Redewendungen verlangen, dass (wahr) ... Pause. Zum Beispiel Ereignisschleifen, bei denen die Ausgangsbedingung nicht sauber in die Bedingung passt und Sie je nach Signal möglicherweise eine andere Verarbeitung durchführen möchten, bevor Sie brechen.
krasische

4

Nein, es ist keine schlechte Praxis, aus einer Schleife auszubrechen, wenn eine bestimmte gewünschte Bedingung erreicht ist (wie wenn eine Übereinstimmung gefunden wird). Oft möchten Sie möglicherweise die Iterationen stoppen, weil Sie bereits das erreicht haben, was Sie möchten, und es keinen Sinn macht, weiter zu iterieren. Achten Sie jedoch darauf, dass Sie nicht versehentlich etwas verpassen oder ausbrechen, wenn dies nicht erforderlich ist.

Dies kann auch zu einer Leistungsverbesserung beitragen, wenn Sie die Schleife unterbrechen, anstatt über Tausende von Datensätzen zu iterieren, selbst wenn der Zweck der Schleife abgeschlossen ist (dh möglicherweise besteht die Übereinstimmung mit dem erforderlichen Datensatz bereits).

Beispiel:

for (int j = 0; j < type.size(); j++) {
        if (condition) {
            // do stuff after which you want 

            break; // stop further iteration
        }

}

Sie können eine beschriftete Pause verwenden, um die beiden Schleifen zu beenden:search: for (int i = 0; i < s; i++) { for (int j = 0; j < t.size(); j++) { if (condition) { break search; } } }
Michael Konietzka

ja das weiß ich schon Ich habe es versehentlich gepostet.
Ankur Shanbhag

2

Es ist keine schlechte Praxis, aber es kann dazu führen, dass Code weniger lesbar ist. Eine nützliche Umgestaltung, um dies zu umgehen, besteht darin, die Schleife in eine separate Methode zu verschieben und dann anstelle einer Unterbrechung eine return-Anweisung zu verwenden, z. B. diese (Beispiel aus der Antwort von @ Chris):

String item;

for(int x = 0; x < 10; x++)
{
    // Linear search.
    if(array[x].equals("Item I am looking for"))
    {
        //you've found the item. Let's stop.
        item = array[x];
        break; 
    }
}

kann dazu (mit der Extraktionsmethode ) umgestaltet werden :

public String searchForItem(String itemIamLookingFor)
{
    for(int x = 0; x < 10; x++)
    {
        if(array[x].equals(itemIamLookingFor))
        {
            return array[x];
        }
    }
}

Was sich beim Aufrufen aus dem umgebenden Code als besser lesbar erweisen kann.


2

Wenn Sie anfangen, so etwas zu tun, wird es etwas seltsam und Sie sollten es besser auf eine separate Methode verschieben, returnsdie sich aus der angepassten Bedingung ergibt.

boolean matched = false;
for(int i = 0; i < 10; i++) {
    for(int j = 0; j < 10; j++) {
        if(matchedCondition) {
            matched = true;
            break;
        }
    }
    if(matched) {
        break;
    }
}

Um zu erläutern, wie der obige Code bereinigt wird, können Sie den Code umgestalten und in eine Funktion verschieben, die returnsnicht verwendet wird breaks. Dies ist im Allgemeinen besser im Umgang mit komplexen / chaotischen breaks.

public boolean  matches()
    for(int i = 0; i < 10; i++) {
        for(int j = 0; j < 10; j++) {
            if(matchedCondition) {
                return true;
            }
        }
    }
    return false;
}

Allerdings für etwas Einfaches wie mein Beispiel unten. Auf jeden Fall benutzen break!

for(int i = 0; i < 10; i++) {
    if(wereDoneHere()) { // we're done, break.
        break;
    }
}

Wenn Sie im obigen Fall die Bedingungen iund jden Wert ändern , wird der Code nur schwer lesbar. Es könnte auch einen Fall geben, in dem die Obergrenzen (im Beispiel 10) Variablen sind, sodass es noch schwieriger ist zu erraten, auf welchen Wert sie gesetzt werden müssen, um die Schleife zu verlassen. Man könnte natürlich einfach eingestellt iund jauf Integer.MAX_VALUE, aber ich denke , Sie dies beginnt sehen chaotisch sehr schnell. :) :)


Das Refactoring der "separaten Methode" verdient besondere Beachtung. Wenn Sie befürchten, dass ein Codeabschnitt aus irgendeinem Grund schwer zu lesen ist, kann es hilfreich sein, ihn in eine eigene Methode zu extrahieren. Im Kontext dieser Frage kann es auch die breakAussagen in returnAussagen umwandeln .
Russell Silva

1
@RussellSilva Danke, ich werde bearbeiten, um die Betonung hinzuzufügen.
Kenny Cason

Ihr erster Fall könnte durch eine Unterbrechung der Kennzeichnung vereinfacht werden. Einige Leute mögen es nicht, weil es sich wie ein anfühlt goto, aber dies ist einer der Fälle, in denen das besonders nützlich ist.
Darrel Hoffman

@DarrelHoffman Das könnten Sie sicherlich tun, aber ich denke, es zu einer separaten Methode zu machen und zurückzukehren, ist die "Standard" -Methode, um damit umzugehen, zumindest in Java.
Kenny Cason

2

Es gibt eine Reihe gängiger Situationen, für die breakder Algorithmus am natürlichsten ausgedrückt werden kann. Sie werden "eineinhalb Schleifen" -Konstrukte genannt; Das Paradigmenbeispiel ist

while (true) {
    item = stream.next();
    if (item == EOF)
        break;
    process(item);
}

Wenn Sie dies nicht verwenden breakkönnen, müssen Sie sich stattdessen wiederholen:

item = stream.next();
while (item != EOF) {
    process(item);
    item = stream.next();
}

Es besteht allgemein Einigkeit darüber, dass dies schlimmer ist.

In ähnlicher Weise continuegibt es ein allgemeines Muster, das so aussieht:

for (item in list) {
    if (ignore_p(item))
        continue;
    if (trivial_p(item)) {
        process_trivial(item);
        continue;
    }
    process_complicated(item);
}

Dies ist oft besser lesbar als die Alternative mit verkettet else if, insbesondere wenn process_complicatedmehr als nur ein Funktionsaufruf vorliegt.

Weiterführende Literatur: Loop-Exits und strukturierte Programmierung: Wiedereröffnung der Debatte


1

Nein, das ist keine schlechte Praxis. Dies ist der einfachste und effizienteste Weg.


4
Es könnte aber auch der am wenigsten lesbare Weg sein. Solche pauschalen Aussagen sind in einer signifikanten Teilmenge von Fällen normalerweise falsch .
Stephen C

Es hängt von Ihrem ab logic. Manchmal möchten Sie eine Schleife aufgrund eines Flags oder Ähnlichem abnormal beenden. In diesem Fall breakist eine gute Option.
user2550754

1

Es ist zwar keine schlechte Praxis, Pause zu verwenden, und es gibt viele hervorragende Verwendungsmöglichkeiten dafür, aber es sollte nicht alles sein, worauf Sie sich verlassen können. Fast jede Verwendung einer Unterbrechung kann in die Schleifenbedingung geschrieben werden. Code ist weitaus besser lesbar, wenn reale Bedingungen verwendet werden. Bei einer langen oder Endlosschleife sind Unterbrechungen jedoch durchaus sinnvoll. Sie sind auch bei der Suche nach Daten sinnvoll, wie oben gezeigt.


1

Wenn Sie im Voraus wissen , wo wird die Schleife zu stoppen, wird es wahrscheinlich die Lesbarkeit des Codes verbessern den Zustand , in dem zu erklären for, whileoder `do-whileSchleife.

Ansonsten ist das der genaue Anwendungsfall für break.


1

breakund continuebricht die Lesbarkeit für den Leser, obwohl es oft nützlich ist. Nicht so sehr wie "goto" -Konzept, aber fast.

Wenn Sie einige neue Sprachen wie Scala (inspiriert von Java und funktionale Programmiersprachen wie Ocaml) verwenden, werden Sie dies bemerken breakund continueeinfach verschwinden.

Insbesondere bei der funktionalen Programmierung wird dieser Codestil vermieden:

Warum unterstützt Scala Break and Continue nicht?

Zusammenfassend: breakund continuewerden in Java häufig für einen imperativen Stil verwendet, aber für alle Codierer, die früher funktionale Programmierung praktizierten, könnte es seltsam sein.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.