Ich habe oft gehört, dass die Verwendung von break
s in Java als schlechte Übung gilt, aber nachdem ich einige Threads auf Stack Overflow gelesen habe, habe ich etwas anderes gesehen. Viele sagen, dass es in bestimmten Fällen akzeptabel ist.
Ich bin etwas verwirrt darüber, was in diesem Fall schlecht ist / ist.
Für Project Euler : Problem 7, ich habe den folgenden Code erstellt. Die Herausforderung bestand darin, die 10001. Primzahl zu finden.
%Vor%Dies liefert die korrekte Antwort (in 21ms), aber übersehe ich eine ernste Warnung? Es ist 100% möglich, eine While-Schleife ohne Pause zu erstellen, aber ich finde, dass dies ein wenig einfacher zu folgen ist.
Benutzt ich die break;
schlechte Übung? Ich weiß, dass es immer einen Weg gibt, einen zu benutzen, aber ist es wirklich so schlimm hier?
Vielen Dank
Justian
BEARBEITEN
Hier ist mein isPrime () Code. Ich könnte das auch optimieren, während ich dabei bin.
%Vor% In diesem Fall sieht es für mich so aus, als ob es einfacher wäre, die Bedingung while
zu ändern:
Das ist normalerweise der Fall, wenn eine while(true)
Schleife mit
... obwohl Sie prüfen müssen, ob etwas anderes im Schleifenkörper ein continue
ausführt.
Alternativ könnten Sie es leicht umstrukturieren:
%Vor% Dann wird current
die Antwort am Ende sein.
Im Allgemeinen bevorzuge ich eine for
-Schleife über eine while-Schleife, wenn Sie versuchen, eine bestimmte Anzahl von Malen zu tun. In diesem Fall ist das "Etwas" "finde die nächste Primzahl".
Es gibt verschiedene Dogmen in der Programmierung, von denen ich glaube, dass sie zu weit gefasst sind - einschließlich "eines Ausgangspunkts für eine Methode" und "keine Pause verwenden". Schreibe den Code so gut wie möglich. Wenn du dir Code anschaust und merkst, dass es nicht offensichtlich ist, was los ist, versuche, andere Wege zu finden, ihn zu strukturieren. Manchmal ist es ein Fall, eine Schleife zu ändern; manchmal extrahiert es eine Methode; manchmal invertiert es eine Logik (gehe zuerst mit einem negativen Zweig um, wähle möglicherweise früh und bearbeite dann den Normalfall).
Ich bin mir nicht sicher, ob Pausen im Allgemeinen eine schlechte Übung sind, aber ich denke, dass dies eine ist.
Es ist ein bisschen albern, weil es unnötig ist. Ihr while (true) ... break
entspricht vollständig:
aber viel weniger intuitiv.
Wenn Sie sich an den kanonischen Weg zur Darstellung von Dingen halten, bedeutet das weniger Rechenaufwand für Ihre Leser, macht Ihren Code verständlicher, einfacher zu pflegen und letztendlich robuster.
Bearbeiten (als Antwort auf einen Kommentar): Sie haben Recht, dass es immer einen Weg gibt, einen zu verwenden, aber die Regel (wenn Sie einen wollen) ist relativ einfach: Schreiben Sie, was am besten lesbar ist. In dem Fall, dass Sie gepostet haben, ist dies nicht der lesbarste, da die Alternative, die ich gab, die kanonische Art ist, dies zu repräsentieren. In einigen Fällen, zum Beispiel durch eine Sammlung, bis Sie einen bestimmten passenden Kandidaten gefunden haben, ist die Verwendung von break
wahrscheinlich der beste Weg, dieses Muster darzustellen.
Es wäre schwierig (und ich würde argumentieren, vergeblich), zu versuchen, sich mit festen Regeln darüber zu befassen, wann break
verwendet werden soll und wann man Variablen herausziehen und stattdessen Konditionale verwenden soll. Oft ist es einfach zu sagen, was die einfachste Option ist, aber nicht immer. Dies ist eines der Beispiele, wo Erfahrung wirklich zählt - je mehr guten / schlechten Code du gelesen und selbst geschrieben hast, desto größer deine persönliche Bibliothek an guten und schlechten Beispielen und desto einfacher wird es für dich sein zu sagen, was das "Beste" ist "* Möglichkeit, ein gegebenes Konzept darzustellen.
* Natürlich ist es subjektiv!
Es gibt ein paar Bedingungen, wenn es sinnvoll ist, eine Pause zu machen. Eine ist, wenn Sie N.5-Loops ausführen müssen - d. H., Sie werden die Schleife einige Male ausführen, aber das letzte Mal werden Sie immer irgendwo in der Mitte des Loop-Körpers ausgeführt. Sie können > vermeiden, in diesem Fall eine Pause zu verwenden, aber dies verschleiert oft den Code oder führt zu einer Duplizierung. Zum Beispiel:
%Vor%kann wie folgt aussehen:
%Vor%oder:
%Vor%Keine davon ist notwendigerweise eine wesentliche Verbesserung. Ein anderer Umstand, unter dem eine Pause sinnvoll sein kann, ist einfach ein Fehler. Wenn Sie beispielsweise N Dateien zur Verarbeitung übergeben haben, kann es sinnvoll sein, die Schleife zu verlassen, wenn eine der Dateien nicht geöffnet werden kann. Nichtsdestoweniger, wenn es überhaupt sinnvoll ist , ist es eindeutig besser, die Bedingung zu haben, unter der Sie die Schleife verlassen, die explizit in der Bedingung der Schleife angegeben ist.
Wenn es nur eine Bedingung gibt, unter der eine Schleife beendet werden kann, und vor der Überprüfung der Bedingung nicht viel Code ausgeführt werden muss und nicht viel Code ausgeführt werden muss Überprüfen Sie die Bedingung, setzen Sie die Bedingung in die Schleife.
Ich denke, es gibt sicherlich Anwendungen für ein "do {} while (1);" Schleife. Unter ihnen:
Manche Leute benutzen gerne Flags, um Ausgangsbedingungen zu unterscheiden. Ich neige dazu, solche Flags als eine Bemühung zu betrachten, die Codierungsstrukturen zu vermeiden, die tatsächlich die Aktion des Programms am besten verkörpern.
Wenn man sich keine Gedanken über die Geschwindigkeit macht, kann man vermeiden, jemals irgendeine Form von goto , vorzeitigem Beenden return zu verwenden, oder für mehrere Zwecke während - und das mit einer einfachen Bedingung. Schreiben Sie einfach das gesamte Programm als Zustandsmaschine:
%Vor%Es gibt Zeiten, in denen ein solches Codieren nützlich ist (insbesondere wenn das "while" aus der Routine do_whatever () in eine Schleife gezogen werden kann, die mehrere ähnlich codierte Routinen "simultan" ausführt). Und es ist nie nötig, etwas wie ein "Goto" zu verwenden. Aber zur besseren Lesbarkeit sind strukturierte Programmierkonstrukte viel netter.
Meiner Meinung nach ist das Ersetzen eines strukturierten Codes durch unstrukturierten Code ein Flag, um eine Schleife zu beenden und dann einen von mehreren Codeteilen auszuwählen, die basierend auf der Beendigungsursache ausgeführt werden. Wenn ich innerhalb einer Schleife schreibe, schreibe ich
%Vor%Es ist sofort (und lokal) klar, dass der Grund, warum ich ein neues Objekt erstelle, darin liegt, dass mein Index die Anzahl der Elemente überschritten hat und ich keine redundante Bedingung testen muss. Wenn ich stattdessen eine Schleife mache, bis ich etwas gefunden habe oder keine Elemente mehr habe, dann muss ich entweder eine Bedingung nach der Schleife redundant testen oder jeder Schleifeniteration einen Flag-Test hinzufügen.
Wie andere bemerkt haben, ist das Beispiel, das Sie angegeben haben, ein schlechtes, weil Sie den Test einfach in den WHILE verschieben können.
Die Fälle, in denen ich eine Pause benutze, sind wenn ich eine Schleife habe, in der ich etwas verarbeiten muss, bevor ich weiß, dass dies das letzte Mal ist. Zum Beispiel:
%Vor%Dieses Beispiel ist nur leicht erfunden: Ich stoße oft auf Probleme, wenn ich Daten aus einer Datei oder einer anderen Quelle lese, diese Daten irgendwie parse und erst dann weiß, dass ich das Ende erreicht habe, an dem ich interessiert bin Verarbeitung jetzt.
Sie könnten natürlich eine Funktion schreiben, die die Zeile liest und das Parsen benötigt, wie:
%Vor%Aber dann haben Sie möglicherweise das Problem, dass sowohl die Funktion als auch der Körper der Schleife Zugriff auf die gelesenen Daten benötigen, und die Funktion muss einen booleschen Wert für die Regelkreisverarbeitung zurückgeben, so dass sie die Daten nicht zurückgeben kann Um die Daten für den Schleifenkörper verfügbar zu machen, muss die Funktion in ein für beide Seiten zugängliches Feld geworfen werden, das dann verdeckt, woher die Schleife ihre Daten bezieht.
Diese Lösung ist ziemlich schnell:
%Vor%Anmerkungen: