If-Else VS Schalten Sie das Flussende um

8

Ich habe mich gefragt , ob die if-else - Anweisungen, wie eine switch - Anweisung ist , das tut eine Pause Äußerung.

if( boolean_expression_1 )
  statement_1
else if( boolean_expression_2 )
  statement_2
else 
  default_statement

Ist das gleiche wie:

switch( controlling_expression )
{
case: ( boolean_expression_1 )
{
     statement_1
     break;
}
case: ( boolean_expression_2 )
{
     statement_2
     break;
}
default:
{
     default_statement
}
Chris Okyen
quelle
Die Frage wurde dahingehend geändert, was ich wirklich meinte, was das Gegenteil von dem war, was ich ursprünglich gestellt hatte. Beispiel bearbeitet, um der beabsichtigten Frage zu entsprechen. Ich weiß, einige von Ihnen haben geantwortet, ob die beiden Aussagen scheinbar gleich waren, und andere haben geantwortet, ob sie buchstäblich gleich waren. Ich schätze beides, da es einen Blickwinkel auf vorweggenommene Ähnlichkeiten gibt und auch darauf, was sie (unterschiedlich / gleich) tief im
Inneren
Wenn Sie diese Art von Konstrukten interessant finden, würde ich Ihnen dringend empfehlen, sich die Bedingungen und Schutzvorrichtungen für die Musterübereinstimmung anzusehen. Die Konzepte sind sehr ähnlich, können aber wunderbar ausdrucksstark sein. Ich kenne sie in F #, aber in der JVM glaube ich, dass Scala sie unterstützt.
Steven Evers

Antworten:

6

Ich habe mich gefragt, ob die if-else-Anweisungen wie eine switch-Anweisung sind, die keine break-Anweisung enthält.

Das ist rückwärts. So'ne Art.

Eine if, else if, ... else-Sequenz, in der alle Tests einfache Gleichheitstests für dieselbe Variable des Formulars sind (variable == value)oder ((variable == value1) || (variable == value2) ...)in eine switch-Anweisung für diese Variable konvertiert werden können. Die (variable == value)Tests werden case value:und der Körper des if(oder else if) wird zum Körper des Falls, aber Sie müssen breakam Ende des Fallkörpers eine Anweisung hinzufügen . Die ((variable == value1) || (variable == value2) ...)Tests werden zu einer Folge von Fällen der Form case value1: case value2: ... case valuen:Eine if-Folge mit komplexeren Tests unterscheidet sich im Allgemeinen von einer switch-Anweisung.

Wenn jeder Fall in einer switch-Anweisung mit endet break, kann diese switch-Anweisung immer als if-, else if, ... -Sequenz umgeschrieben werden. Diese Umwandlung von einem Wechsel in eine if-Sequenz ist auch möglich, wenn das Durchfallen auf Dinge wie case A: case B: ... case N: do_something(); break;Fall Through beschränkt ist, bei denen ein nicht leerer Körper in einen anderen nicht leeren Körper durchfällt, und nicht direkt in eine if-Sequenz konvertierbar ist.

David Hammen
quelle
Vielen Dank. if-else-Anweisungen sind wahrgenommene / scheinbar switch (...) Anweisungen mit einer Unterbrechung an jedem Ende jedes Fallkörpers. Mehrere if-Anweisungen allein ohne ein else-Paar sind wahrgenommene / scheinbar switch (...) -Anweisungen ohne Unterbrechungen am Ende jedes Fallkörpers . Ich würde beschreiben, wie es wahrgenommen wird, indem ich die Details der Verschachtelung hinzufüge, aber das wäre nicht möglich, um den Teil dieser Frage zu kauen.
Chris Okyen
3

Obwohl es für einen neuen Programmierer eine hilfreiche Abstraktion ist, einen if-else-Block als eine switch-Anweisung ohne Unterbrechung zu betrachten, ist dies kein perfekter Vergleich.

Switch ist wahrscheinlich enger mit "goto" verwandt. Zugegeben, Java hat kein Springen, aber die Sprache wurde auf Ideen aus anderen Sprachen wie C aufgebaut. Die Bezeichnungen "case" und "default" unterscheiden sich nicht wirklich von anderen Sprungzielen für eine goto-Anweisung. Das erwartete Verhalten besteht also darin, die nächste Codezeile innerhalb des Blocks weiter auszuführen (die gesamte switch-Anweisung ist der Block). . Dies wird in einer der Antworten auf eine verwandte Frage weiter erläutert: Warum müssen wir Break-In-Schalter verwenden? Wir haben also den Fall, dass Sie eine break-Anweisung benötigen, um Ihrem Programm mitzuteilen, dass Sie mit der Ausführung dieses Blocks fertig sind. Sie können break in anderen Arten von Anweisungen verwenden, z. B. eine for- oder while-Schleife.

In Sprachen wie Java, die Kurzschlüsse verwenden, werden in einem if-elseif-else-Block die else if- und else-Blockbedingungen nicht ausgewertet, wenn die Bedingung für den ersten Fall der if-Anweisung wahr ist. Nach einem if wird erwartet, dass Sie entweder einen Codeblock in Klammern {} oder eine einzelne Anweisung finden. Per Definition bedeutet sonst "anders" oder dass die vorherige Bedingung nicht wahr ist, es wäre ein bisschen widersprüchlich, den Code durchfallen zu lassen.

Jessica Brown
quelle
"Obwohl es für einen neuen Programmierer eine hilfreiche Abstraktion sein könnte, einen 'if-else'-Block als eine' switch-Anweisung 'ohne Unterbrechung zu betrachten, ist dies kein perfekter Vergleich." - Meinst du nicht "einen 'if-else'-Block als eine' switch-Anweisung ' mit einer Pause zu betrachten ...?"
Chris Okyen
Der Widerspruch ist richtig!
Chris Okyen
1

Programmiersprachen bieten häufig viele verschiedene Konstrukte, mit denen Sie ähnliche Logik mit unterschiedlicher Syntax ausdrücken können.

if/ elseAussagen "fallen" nicht bedingungslos miteinander durch; Das Schlüsselwort else verhindert, dass weitere else-ifBedingungen ausgewertet werden, breaksobald Sie am Ende eines Fallblocks aus einem Schalter aussteigen. Wenn Sie jedoch eine Reihe von eigenständigen Bedingungen if(ohne Verwendung else) erstellen, wird jede ifBedingung für sich ausgewertet.

Umgekehrt führt das Entfernen des breakSchlüsselworts vom Ende Ihrer caseBlöcke dazu, dass der Ausführungsfluss bedingungslos zum nächsten Fall weitergeht, bis entweder eine Unterbrechung / Rückgabe / Goto auftritt oder das Ende des Schaltblocks erreicht ist.

Es gibt (selten) Situationen, in denen das Durchfallen von Schaltkästen als nützlich angesehen wird. Es ist jedoch üblicher und normalerweise idiomatischer, wenn jeder Fallblock für sich behandelt werden soll.

if-elseund switch-casesind beide Konstrukte, mit denen Sie Auswahl (Entscheidungsfindung) in einer Programmiersprache ausdrücken können; Manchmal hängt die Wahl zwischen den beiden vom persönlichen Stil ab, manchmal gibt es zwingende Gründe, sich für eine andere zu entscheiden. Eine ähnliche Wahl gibt es, wenn Sie für -vs- wählen, während Sie Wiederholungen ausdrücken.

Ben Cottrell
quelle
Vielen Dank. Ein Beispiel für Situationen, in denen ein Switch-Case durchfällt, wird als nützlich angesehen, wenn Sie möchten, dass ein Fall etwas tut und möglicherweise nach einem echten Ergebnis für diesen Fall etwas weiter passiert, wenn der nächste Fall auch wahr ist ... Schalter (i) Fall: A {Pause; } case: B {....} case: C {.... break} Wenn also B auftritt und dann die Möglichkeit des Auftretens von C zulässt ...
Chris Okyen
0

Die Antwort lautet nein - die if-Anweisung ist nicht wie eine switch-Anweisung ohne Unterbrechung. Beginnen wir mit diesem Teil Ihrer Frage:

Wenn boolean_expression_1 wahr wäre, würde es prüfen, ob boolean_expression_2 wahr ist?

Wir können die Antwort mit diesem Programm finden. Der Trick ist, dass wir eine Methode als unseren booleschen Ausdruck aufrufen und System.out.println () verwenden, um zu sehen, ob die Methode ausgeführt wird. Auf diese Weise wissen wir, ob der Ausdruck ausgewertet wurde. Hier ist das Programm:

public class IfElseExample {

    private static boolean booleanExpression1() {
        System.out.println("Expression 1 is being evaluated.");
        return true;
    }

    private static boolean booleanExpression2() {
        System.out.println("Expression 2 is being evaluated.");
        return true;
    }

    public static void main(String[] args) {
        if (booleanExpression1()) 
            System.out.println("Statement 1 is executed");
        else if (booleanExpression2()) 
            System.out.println("Statement 2 is executed");
        else
            System.out.println("Default statement is executed");
    }

}

Sie werden sehen, dass der zweite boolesche Ausdruck nicht ausgewertet wird. Dieses Verhalten wird wahrscheinlich verständlicher, wenn Sie einige Klammern setzen (was in den meisten Fällen eine gute Angewohnheit ist):

    if (booleanExpression1()) { 
        System.out.println("Statement 1 is executed");
    } else {
        if (booleanExpression2()) {
            System.out.println("Statement 2 is executed");
        } else {
            System.out.println("Default statement is executed");
        }
    }

Auf diese Weise zeigt der Compiler Ihre ursprüngliche if-Kette an. Wie Sie jetzt sehen können, ist das zweite "if" eine einzelne Anweisung für sich und befindet sich als solche nicht auf derselben Ebene wie die erste if-Anweisung. Wenn Sie mehr if-Anweisungen verketten, werden diese noch tiefer verschachtelt.

Sie haben auch gefragt, warum die switch-Anweisung eine break-Anweisung benötigt. Dies liegt daran, dass die switch-Anweisung nicht intern mit einer Kette von if-Anweisungen implementiert wird (und die if-Anweisung basiert auch nicht auf switch-Anweisungen). Das könnte man erwarten

        switch(controllingExpression()) {
            case 42: System.out.println("A");
                        case 43: System.out.println("B");
            default : System.out.println("z");
        }

wird vom Compiler in etwas übersetzt wie:

if (controllingExpression() == 42) {
    System.out.println("A");
} else if (controllingExpression() == 43) {
    System.out.println("B");
} else {
    System.out.println("z");
}

Das ist nicht der Fall. Stattdessen wird eine versteckte Skip-Anweisung verwendet:

int x = numberOfStatementsToSkipFor(controllingExpression());
skip x // hidden skip the next x statements byte code instruction
System.out.println("A");
System.out.println("B");
System.out.println("z");

Die Methode numberOfStatementsToSkipFor () gibt 0 für 42, 1 für 43 und 2 für alles andere zurück. Jetzt wird klar, warum dieses Programm produzieren könnte

A
B
z

oder

B
z

oder nur

z

aber nie

A
B

ohne das 'z'. Aber natürlich wäre es schön, wenn wir das schaffen könnten. Und wir können break verwenden, das in eine andere Skip-Anweisung übersetzt wird. Also, wenn Sie alle Fallzweige unterbrechen

switch(controllingExpression()) {
    case 42: {
        System.out.println("A");
        break;
    }
    case 43: {
        System.out.println("B");
        break;
    }
    default : System.out.println("z");
}

Der Compiler erstellt Folgendes:

int x = numberOfStatementsToSkip(controllingExpression());
skip x; // hidden skip the next x statements byte code instruction
System.out.println("A");
skip 3; //"B" + skip + "z"
System.out.println("B");
skip 1;
System.out.println("z");
Scarfridge
quelle
Danke, ich habe alles bis zum 'int x = numberOfStatementsToSkipFor (ControllingExpression ())' verstanden. Code-Chunk, der beschreibt, wie die nächste x-Anzahl von Bytecode-Anweisungen übersprungen wird, wenn Sie eine switch-Anweisung haben, wie Sie gezeigt haben. Wandelt der Compiler die switch-Anweisung in Code um, der ihn auffordert, X # des Bytecodes zu überspringen, und die JVM tut dies?
Chris Okyen
Ich verstehe auch nicht, wie dieser Sprungvorgang funktioniert ... Ich kenne einige M6800-Asm, es ist, als würde man den Zeiger auf den Betrag des Aufrufstapels X springen ... Werden nicht alle Anweisungen der beiden Fälle und der Standardeinstellung so aufgerufen warum sollten sie übersprungen werden. Woher weiß es, sie zu überspringen. Und warum haben Sie nur die Anweisungen (oder Aktionen) übersprungen, die aufgerufen wurden, weil die Fälle wahr sind? Muss der Schaltercode {und case: code und default: and} nicht übersprungen werden oder ist das nicht real? "Opcode", aber nur Logik in übergeordneten Programmiersprachen wie C und Java und Pascal?
Chris Okyen
@ ChrisOkyen Ich habe versucht, das Grundkonzept zu veranschaulichen. Die tatsächliche Realisierung in der JVM wird hier beschrieben: artima.com/underthehood/flowP.html
scarfridge
0

Um die bearbeitete Frage zu beantworten (mit den Pausen)

Sie würden die Anweisungen genau dann gleich bewerten, wenn die Bedingungen für die Eingabe jedes Blocks gleich sind.

Um die subjektive Frage zu beantworten, von

gibt einen Denkwinkel über erhaltene Ähnlichkeiten und auch darüber, was sie (unterschiedlich / gleich) tief im Inneren sind

Der Vergleich der beiden lenkt Sie von dem ab, was jeder schnell ausdrücken soll.

A switchzentralisiert den Vergleich syntaktisch, sodass Sie den Ablauf anhand seiner Fälle verfolgen können.

Während a ifeine einzelne Bedingung zum Eingeben eines Blocks beschreibt.

Grundsätzlich "liest" der Code nur anders.

Zum Beispiel haben Sie ein wordim Kopf und möchten es im Wörterbuch nachschlagen.

Ein Schalter würde lauten: Halten Sie den Startbuchstaben in Ihrem Kopf und blättern Sie dann durch das Alphabet. Geben Sie dann auf, wenn er nicht mit diesem Buchstaben beginnt.

Während eine Reihe von if-else-Blöcken lauten würde: Beginnt das Wort mit einem Buchstaben? viele Male wiederholt, dann aufgeben.

Wenn Sie versuchen, einem neuen Programmierer zu erklären, wie ein Switch funktioniert (der mit if-Blöcken vertraut ist, ist es möglicherweise einfacher, ihn wie folgt zu erklären:

if( boolean_expression_1 ) {
  statement_1;
  return;
}

if( boolean_expression_2 ) {
  statement_2;
  return;
}

default_statement;
return;

Das vorstehende Beispiel bricht nun das, was normalerweise in Schulen gelehrt wird, aber die frühzeitige Rückkehr und die Rückkehr sind oft einfacher zu lesen und in einem stapelbasierten VM genauso schnell.

Es sollte Optimierungen für das Einschalten von Grundelementen geben, daher sollte die Auswahl des zu verwendenden Blocks davon abhängen, was Sie vergleichen.

Denken Sie daran, dass lange switchund aussagekräftige ifAussagen in der Regel sehr ausführlich und schwer zu pflegen sind und sich auch in der Leistung verschlechtern, da mehr Bedingungen überprüft werden müssten.

Möglicherweise möchten Sie eine Hashanonyme Klasse / Funktion oder ein Befehlsmuster anstelle langwieriger Steuerblöcke mit vielen Bedingungen in Betracht ziehen .

Hashes und Befehlsmuster ermöglichen eine schnellere Ausführung des Codes und verbessern die Wartbarkeit des Codes.

Brian
quelle