Antworten:
Manchmal ist es hilfreich, mehrere Fälle mit demselben Codeblock zu verknüpfen, z
case 'A':
case 'B':
case 'C':
doSomething();
break;
case 'D':
case 'E':
doSomethingElse();
break;
usw. Nur ein Beispiel.
Nach meiner Erfahrung ist es normalerweise ein schlechter Stil, "durchzufallen" und mehrere Codeblöcke für einen Fall ausführen zu lassen, aber in einigen Situationen kann es Verwendungen dafür geben.
// Intentional fallthrough.
wenn Sie eine Pause auslassen. Es ist meiner Meinung nach weniger ein schlechter Stil als "leicht, eine Pause versehentlich zu vergessen". PS Natürlich nicht in einfachen Fällen wie in der Antwort selbst.
case
s auf diese Weise gestapelt werden. Wenn sich dazwischen Code befindet, ist der Kommentar wahrscheinlich verdient.
case
, etwa so: case 'A','B','C': doSomething(); case 'D','E': doSomethingElse();
, ohne eine Pause zwischen den Fällen zu benötigen. Pascal könnte dies tun: "Die case-Anweisung vergleicht den Wert des Ordnungsausdrucks mit jedem Selektor, der eine Konstante, ein Unterbereich oder eine durch Kommas getrennte Liste sein kann." ( wiki.freepascal.org/Case )
Historisch gesehen liegt dies daran, dass im case
Wesentlichen ein definiert wurde label
, der auch als Zielpunkt eines goto
Anrufs bezeichnet wird. Die switch-Anweisung und die zugehörigen Fälle stellen wirklich nur einen Mehrwegezweig mit mehreren potenziellen Eintrittspunkten in einen Codestrom dar.
Trotzdem wurde fast unendlich oft festgestellt, dass dies break
fast immer das Standardverhalten ist, das Sie am Ende eines jeden Falles lieber hätten.
Java kommt von C und das ist die Syntax von C.
Es gibt Zeiten, in denen mehrere case-Anweisungen nur einen Ausführungspfad haben sollen. Unten sehen Sie ein Beispiel, das Ihnen sagt, wie viele Tage in einem Monat.
class SwitchDemo2 {
public static void main(String[] args) {
int month = 2;
int year = 2000;
int numDays = 0;
switch (month) {
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
numDays = 31;
break;
case 4:
case 6:
case 9:
case 11:
numDays = 30;
break;
case 2:
if ( ((year % 4 == 0) && !(year % 100 == 0))
|| (year % 400 == 0) )
numDays = 29;
else
numDays = 28;
break;
default:
System.out.println("Invalid month.");
break;
}
System.out.println("Number of Days = " + numDays);
}
}
Ich denke es ist ein Fehler. Als Sprachkonstrukt ist es genauso einfach break
wie das Standardkonstrukt und hat stattdessen ein fallthrough
Schlüsselwort. Der größte Teil des Codes, den ich geschrieben und gelesen habe, hat nach jedem Fall eine Pause.
continue <case name>
welche explizit angeben kann, mit welcher case-Anweisung fortgefahren werden soll.
case
innerhalb des Stroms zugelassen wird switch
, wird dies einfach zu einem goto
. ;-)
Sie können alle möglichen interessanten Dinge mit Fallfall tun.
Angenommen, Sie möchten eine bestimmte Aktion für alle Fälle ausführen, aber in einem bestimmten Fall möchten Sie diese Aktion plus etwas anderes ausführen. Die Verwendung einer switch-Anweisung mit Fall-Through würde dies recht einfach machen.
switch (someValue)
{
case extendedActionValue:
// do extended action here, falls through to normal action
case normalActionValue:
case otherNormalActionValue:
// do normal action here
break;
}
Natürlich ist es leicht, die break
Aussage am Ende eines Falles zu vergessen und unerwartetes Verhalten zu verursachen. Gute Compiler werden Sie warnen, wenn Sie die break-Anweisung weglassen.
Warum setzt der Compiler nicht automatisch break-Anweisungen nach jedem Codeblock im Switch?
Abgesehen von dem guten Wunsch, den identischen Block für mehrere Fälle verwenden zu können (die speziell behandelt werden könnten) ...
Ist es aus historischen Gründen? Wann sollen mehrere Codeblöcke ausgeführt werden?
Es dient hauptsächlich der Kompatibilität mit C und ist wohl ein uralter Hack aus alten Zeiten, als goto
Schlüsselwörter die Erde durchstreiften. Es tut einige erstaunliche Dinge ermöglichen, natürlich, wie Duff Gerät , aber ob das ist ein Punkt zu seinen Gunsten oder gegen ist ... argumentative am besten.
Das break
nach dem Einschalten case
s wird verwendet , um den Durchfall in den Switch - Anweisungen zu vermeiden. Interessanterweise kann dies jetzt durch die neu gebildeten Switch-Labels erreicht werden, die über JEP-325 implementiert wurden .
Mit diesen Änderungen kann das break
mit jedem Schalter case
vermieden werden, wie weiter gezeigt wird:
public class SwitchExpressionsNoFallThrough {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int value = scanner.nextInt();
/*
* Before JEP-325
*/
switch (value) {
case 1:
System.out.println("one");
case 2:
System.out.println("two");
default:
System.out.println("many");
}
/*
* After JEP-325
*/
switch (value) {
case 1 ->System.out.println("one");
case 2 ->System.out.println("two");
default ->System.out.println("many");
}
}
}
Bei Ausführung des obigen Codes mit JDK-12 könnte die Vergleichsausgabe als angesehen werden
//input
1
// output from the implementation before JEP-325
one
two
many
// output from the implementation after JEP-325
one
und
//input
2
// output from the implementation before JEP-325
two
many
// output from the implementation after JEP-325
two
und natürlich die Sache unverändert
// input
3
many // default case match
many // branches to 'default' as well
Sie müssen den Code also nicht wiederholen, wenn Sie mehrere Fälle benötigen, um dasselbe zu tun:
case THIS:
case THAT:
{
code;
break;
}
Oder Sie können Dinge tun wie:
case THIS:
{
do this;
}
case THAT:
{
do that;
}
In einer Kaskadenart.
Wirklich fehleranfällig, wenn Sie mich fragen.
do this
und do that
dafür aber nur do that
dafür?
Was die historischen Aufzeichnungen betrifft, hat Tony Hoare die Fallbeschreibung in den 1960er Jahren während der Revolution der "strukturierten Programmierung" erfunden. Tonys case-Anweisung unterstützte mehrere Labels pro Fall und das automatische Beenden ohne stinkende break
Anweisungen. Die Anforderung für eine explizite break
war etwas, das aus der BCPL / B / C-Linie kam. Dennis Ritchie schreibt (in ACM HOPL-II):
Zum Beispiel war der Endfall, der einer BCPL-Switchon-Anweisung entgeht, nicht in der Sprache vorhanden, als wir ihn in den 1960er Jahren lernten, und daher ist die Überladung des Schlüsselworts break, um der B- und C-switch-Anweisung zu entkommen, eher auf eine unterschiedliche Entwicklung als auf ein Bewusstsein zurückzuführen Veränderung.
Ich konnte keine historischen Schriften über BCPL finden, aber Ritchies Kommentar legt nahe, dass dies break
mehr oder weniger ein historischer Unfall war. BCPL hat das Problem später behoben, aber vielleicht waren Ritchie und Thompson zu beschäftigt, Unix zu erfinden, um sich mit einem solchen Detail zu beschäftigen :-)
break
die Ausführung von "mehreren Codeblöcken" ermöglicht, und befasst sich mehr mit der Motivation dieser Entwurfswahl. Andere erwähnten das bekannte Erbe von C bis Java, und diese Antwort trieb die Forschung noch weiter in die Zeit vor C. Ich wünschte, wir hätten dieses (wenn auch sehr primitive) Muster von Anfang an.
Java leitet sich von C ab, dessen Erbe eine als Duff's Device bekannte Technik umfasst . Es ist eine Optimierung, die auf der Tatsache beruht, dass die Kontrolle von einem Fall zum nächsten fällt, wenn keine break;
Aussage vorliegt. Zu der Zeit, als C standardisiert wurde, gab es eine Menge solchen Codes "in the wild", und es wäre kontraproduktiv gewesen, die Sprache zu ändern, um solche Konstruktionen zu brechen.
Wie die Leute bereits sagten, ist es ein Durchfallen und es ist kein Fehler, es ist eine Funktion. Wenn Sie zu viele break
Anweisungen stören, können Sie sie leicht entfernen, indem Sie stattdessen return
Anweisungen verwenden. Dies ist eigentlich eine gute Vorgehensweise, da Ihre Methoden so klein wie möglich sein sollten (aus Gründen der Lesbarkeit und Wartbarkeit), sodass eine switch
Anweisung bereits groß genug für eine Methode ist. Daher sollte eine gute Methode nichts anderes enthalten ein Beispiel:
public class SwitchTester{
private static final Log log = LogFactory.getLog(SwitchTester.class);
public static void main(String[] args){
log.info(monthsOfTheSeason(Season.WINTER));
log.info(monthsOfTheSeason(Season.SPRING));
log.info(monthsOfTheSeason(Season.SUMMER));
log.info(monthsOfTheSeason(Season.AUTUMN));
}
enum Season{WINTER, SPRING, SUMMER, AUTUMN};
static String monthsOfTheSeason(Season season){
switch(season){
case WINTER:
return "Dec, Jan, Feb";
case SPRING:
return "Mar, Apr, May";
case SUMMER:
return "Jun, Jul, Aug";
case AUTUMN:
return "Sep, Oct, Nov";
default:
//actually a NullPointerException will be thrown before reaching this
throw new IllegalArgumentException("Season must not be null");
}
}
}
Die Ausführung druckt:
12:37:25.760 [main] INFO lang.SwitchTester - Dec, Jan, Feb
12:37:25.762 [main] INFO lang.SwitchTester - Mar, Apr, May
12:37:25.762 [main] INFO lang.SwitchTester - Jun, Jul, Aug
12:37:25.762 [main] INFO lang.SwitchTester - Sep, Oct, Nov
wie erwartet.
Wenn der Compiler keine automatische Unterbrechung hinzufügt, können Sie einen Schalter / Fall verwenden, um auf Bedingungen zu testen, z. B. 1 <= a <= 3
indem Sie die Unterbrechungsanweisung von 1 und 2 entfernen.
switch(a) {
case 1: //I'm between 1 and 3
case 2: //I'm between 1 and 3
case 3: //I'm between 1 and 3
break;
}
Es ist eine alte Frage, aber tatsächlich bin ich heute auf die Verwendung des Falls ohne Unterbrechung gestoßen. Die Nichtverwendung von break ist tatsächlich sehr nützlich, wenn Sie verschiedene Funktionen nacheinander kombinieren müssen.
Beispiel: Verwendung von http-Antwortcodes zur Authentifizierung des Benutzers mit einem Zeit-Token
Server-Antwortcode 401 - Token ist veraltet -> Token neu
generieren und Benutzer anmelden. Server-Antwortcode 200 - Token ist in Ordnung -> Benutzer anmelden.
in case Aussagen:
case 404:
case 500:
{
Log.v("Server responses","Unable to respond due to server error");
break;
}
case 401:
{
//regenerate token
}
case 200:
{
// log in user
break;
}
Auf diese Weise müssen Sie die Anmeldebenutzerfunktion für die 401-Antwort nicht aufrufen, da die Laufzeit bei der Neuerstellung des Tokens in den Fall 200 springt.
Sie können leicht andere Arten von Zahlen, Monaten und Zählungen trennen.
Dies ist besser als in diesem Fall;
public static void spanishNumbers(String span){
span = span.toLowerCase().replace(" ", "");
switch (span){
case "1":
case "jan": System.out.println("uno"); break;
case "2":
case "feb": System.out.println("dos"); break;
case "3":
case "mar": System.out.println("tres"); break;
case "4":
case "apr": System.out.println("cuatro"); break;
case "5":
case "may": System.out.println("cinco"); break;
case "6":
case "jun": System.out.println("seis"); break;
case "7":
case "jul": System.out.println("seite"); break;
case "8":
case "aug": System.out.println("ocho"); break;
case "9":
case "sep": System.out.println("nueve"); break;
case "10":
case "oct": System.out.println("diez"); break;
}
}
Ich arbeite jetzt an einem Projekt, das ich break
in meiner switch-Anweisung benötige , sonst funktioniert der Code nicht. Nehmen Sie mich mit und ich werde Ihnen ein gutes Beispiel dafür geben, warum Sie es break
in Ihrer switch-Anweisung benötigen .
Stellen Sie sich vor, Sie haben drei Zustände, einen, der darauf wartet, dass der Benutzer eine Zahl eingibt, den zweiten, um sie zu berechnen, und den dritten, um die Summe zu drucken.
In diesem Fall haben Sie:
Wenn Sie sich die Zustände ansehen , möchten Sie, dass die Reihenfolge der Genauigkeit bei Zustand1 , dann bei Zustand3 und schließlich bei Zustand2 beginnt . Andernfalls drucken wir nur Benutzereingaben, ohne die Summe zu berechnen. Um es noch einmal zu verdeutlichen, warten wir, bis der Benutzer einen Wert eingibt, berechnen dann die Summe und drucken die Summe aus.
Hier ist ein Beispielcode:
while(1){
switch(state){
case state1:
// Wait for user input code
state = state3; // Jump to state3
break;
case state2:
//Print the sum code
state = state3; // Jump to state3;
case state3:
// Calculate the sum code
state = wait; // Jump to state1
break;
}
}
Wenn wir nicht verwenden break
, wird es in dieser Reihenfolge ausgeführt, state1 , state2 und state3 . Mit verwenden break
wir dieses Szenario jedoch und können in der richtigen Prozedur bestellen, die mit state1, dann state3 und nicht zuletzt state2 beginnt.
break
.