If-Else VS Switchフローの終わり


8

場合-else文、switch文のようなものである場合、私は思っていた break文を持っています。

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

と同じです:

switch( controlling_expression )
{
case: ( boolean_expression_1 )
{
     statement_1
     break;
}
case: ( boolean_expression_2 )
{
     statement_2
     break;
}
default:
{
     default_statement
}

質問を私が本当に意味するものに変更しましたが、どちらが私が元々尋ねたものの反対でした。意図した質問に一致するように例を編集しました。2人の発言が一見同じかどうかを調べた人もいれ文字通り同じかどうかに応じた人もいました。私は両方に感謝します。これは、事前に理解された類似性の角度と、それらが何であるか(異なる/同様)を深く示しているためです
Chris Okyen

これらのタイプのコンストラクトが興味深い場合は、パターンマッチングの条件式とガードを確認することを強くお勧めします。概念は非常に似ていますが、見事に表現することができます。私はF#でそれらに精通していますが、JVMではScalaがそれらをサポートしていると思います。
Steven Evers

回答:


6

if-elseステートメントは、breakステートメントのないswitchステートメントのようなものだと思いました。

それは逆です。やや。

すべてのテストがフォームの同じ変数に対する単純な等価テストである(variable == value)((variable == value1) || (variable == value2) ...)、その変数のスイッチステートメントに変換できるif、else if、... elseシーケンス。(variable == value)テストはなるcase value:、とのボディif(またはelse if)は、ケースの本体になりますが、あなたが追加する必要があるbreakケース本体の末尾に声明を。((variable == value1) || (variable == value2) ...)テストでは、フォームの例のシーケンスになるcase value1: case value2: ... case valuen:、より複雑なテストとの順序は、一般的にはswitch文と区別される場合はアン。

switchステートメントのすべてのケースがで終わる場合break、そのswitchステートメントは常にif、else if、...シーケンスとして書き直すことができます。このスイッチからifシーケンスへの変換は、case A: case B: ... case N: do_something(); break;フォールスルーが空ではないボディから別の空でないボディへのフォールスルーなどに限定されている場合にも可能です。ifシーケンスに直接変換することはできません。


ありがとう。if-elseステートメントは、各ケース本体の各端にブレークがあると認識されている/一見スイッチ(...)ステートメントです。elseペアなしの複数のifステートメントだけが、各ケース本体の終わりに改行なしで認識されている/一見switch(...)ステートメントです。ネストの詳細を追加して、それがどのように認識されるかを説明しますが、それはこの質問のチャンクを噛むのは範囲外です。
Chris Okyen 2012年

3

if-elseブロックを改行のないswitchステートメントのようなものと考えることは、新しいプログラマにとって有用な抽象化かもしれませんが、完全な比較ではありません。

スイッチはおそらく "goto"に密接に関連しています。確かに、JavaにはGotoがありませんが、Cのような他の言語のアイデアに基づいて言語が構築されました。「case」および「default」ラベルは、gotoステートメントの他のジャンプターゲットと実際には何も変わらないため、予想される動作は、ブロック内の次のコード行の実行を継続することです(switchステートメント全体がブロックです)。 。これは、関連する質問の回答の1つでさらに説明されています。なぜスイッチでブレークを使用する必要があるのですか?そのため、このブロックの実行が終了したことをプログラムに伝えるためにbreakステートメントが必要になる場合があります。同様に、forループやwhileループなどの他のタイプのステートメントでbreakを使用できます。

短絡を使用するjavaなどの言語、if-elseif-elseブロックで、ifステートメントの最初のケースの条件がtrueの場合、else ifおよびelseブロックの条件は評価されません。中括弧{}で囲まれたコードのブロックまたは単一のステートメントのいずれかが見つかると予想される場合。定義により、elseは「それ以外の場合」または前の条件が真ではなかったことを意味し、コードを通過させることは少し矛盾します。


「 'if-else'ブロックを中断のない 'switch-statement'のようなものと考えることは、新しいプログラマにとって有用な抽象化であるかもしれませんが、完全な比較ではありません。」-「 'if-else'ブロック、ブレーク付きの 'switch-statement'のようなものと考えている...」という意味ではありませんか?
Chris Okyen、2012年

矛盾は正しいです!
Chris Okyen 2012年

1

プログラミング言語は多くの場合、さまざまな構文を使用して同様のロジックを表現できるようにする多くのさまざまな構造を提供します。

if/ elseステートメントは無条件に相互に「フォールスルー」しません。他のキーワードは任意のさらなる防止else-ifの条件が同じように評価されているbreak場合、ブロックの終わりには、しかし、スタンドアロンのセットの作成、スイッチのあなたを取得しますif(使用せずにSをelseそれぞれ発生します)if条件が独自に評価されます。

逆に、ブロックbreakの最後からキーワードを削除すると、break / return / gotoが検出されるか、switchブロックの最後に到達するまでcase、実行フローが無条件に次のケースに進み続けます。

スイッチケースのフォールスルーが役立つと考えられる状況は(まれに)あります。ただし、これはより一般的であり、通常、各ケースブロックを単独で処理するようにしたほうが慣用的です。

if-elseswitch-caseプログラミング言語で選択(意思決定)を表現できるようにする構成要素です。2つの間の選択が個人的なスタイルになっている場合もあれば、一方を他方よりも選択する説得力のある理由がある場合もあります- 繰り返しを表すために -vs- 選択する場合も同様の選択が存在します。


ありがとう。switch-case fall throughが役立つと考えられる状況の1つの例は、あるケースに何かを実行させ、次のケースにも当てはまる場合に、そのケースの真の結果の後にさらに何かが発生する可能性がある場合です...スイッチ(i)ケース:A {ブレーク; }ケース:B {....}ケース:C {....ブレーク}したがって、Bが発生し、Cが発生する可能性がある場合...
Chris Okyen

0

答えはノーです-ifステートメントは、休憩なしのスイッチステートメントのようなものではありません。あなたの質問のこの部分から始めましょう:

boolean_expression_1がtrueの場合、boolean_expression_2がtrueかどうかを確認しますか?

このプログラムで答えを見つけることができます。コツは、メソッドをboolean_expressionとして呼び出し、System.out.println()を使用して、メソッドが実行されるかどうかを確認することです。このようにして、式が評価されたかどうかを確認します。ここにプログラムがあります:

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");
    }

}

2番目のブール式が評価されないことがわかります。この振る舞いは、いくつかの括弧を入れるとおそらく理解しやすくなります(ほとんどの場合、これは良い習慣です)。

    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");
        }
    }

これは、コンパイラーが元のifチェーンを表示する方法です。ご覧のとおり、2番目の「if」はそれ自体の単一のステートメントであり、最初のifステートメントと同じレベルにはありません。より多くのifステートメントをチェーンすると、それらはさらに深くネストされます。

また、switchステートメントにbreakステートメントが必要な理由も尋ねました。これは、switchステートメントが内部でifステートメントのチェーンを使用して実装されていないためです(どちらもswitchステートメントに基づくifステートメントではありません)。あなたはそれを期待するかもしれません

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

コンパイラによって次のようなものに変換されます:

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

これはそうではありません。代わりに、非表示のスキップステートメントを使用します。

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");

メソッドnumberOfStatementsToSkipFor()は、42の場合は0、43の場合は1、その他すべての場合は2を返します。これで、このプログラムが生成する可能性がある理由が明らかになります

A
B
z

または

B
z

あるいは単に

z

しかし決して

A
B

「z」なし。でもこれができたらいいのは明らかです。そして、breakを使用して、別のskipステートメントに変換できます。したがって、すべてのケースブランチにブレークを入れると

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

コンパイラはこれを生成します:

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");

ありがとう、「int x = numberOfStatementsToSkipFor(controllingExpression());」までのすべてを理解しました。あなたが示したようにswitch文がある場合、次のx個のバイトコード命令をスキップする方法を説明したコードチャンク。コンパイラーは、switchステートメントをバイトコードのX#をスキップするように指示するコードに変換しますか?JVMはスキップしますか?
Chris Okyen 2012

また、このスキッププロセスの仕組みがわかりません... M6800 asmも知っています。これは、ポインタをコールスタックのX量にジャンプするようなものです... 2つのケースのすべてのステートメントとデフォルトが呼び出されるわけではありません。なぜスキップされるのか。それらをスキップすることはどのようにしてわかりますか。そして、なぜtrueの場合のために呼び出されたステートメント(またはアクション)のみをスキップしたのですか...スイッチ{およびcase:コードおよびデフォルト:および}コードはスキップされたopコードである必要があるか、それは本当ではありません「オペコード」だけでなく、ロジックがCやJavaやPascalなどのより高いレベルのプログラミング言語に組み込まれていますか?
Chris Okyen 2012

@ChrisOkyen基本的な概念を説明しようとしていました。JVMでの実際の実現については、こちらで説明しています:artima.com/underthehood/flowP.html
scarfridge

0

編集された質問に回答するには(休憩付き)

各ブロックに入る条件が同じである場合に限り、ステートメントを同じように評価します。

主観的な質問に答えるために

保存された類似性とそれらが何であるか(異なる/類似)の深い角度の考え方の角度を与える

2つを比較すると、それぞれがすばやく表現するために設計されたものから気が散ります。

switch構文的には、あなたがその例に基づいて流れをたどることができるように比較を一元化します。

一方、ifブロックに入る単一の条件を説明します。

基本的に、コードは異なる方法で「読み取る」だけです。

たとえばword、頭にa があり、それを辞書で調べたいとします。

スイッチは次のようになります。最初の文字を頭にかざし、アルファベットを親指でつまみ、その文字で始まらない場合はあきらめます。

if-elseブロックの束は次のようになりますが、単語は文字で始まりますか?何度も繰り返した後、あきらめます。

新しいプログラマー(ifブロックに精通しているプログラマー)にスイッチがどのように機能するかを説明しようとしている場合は、次のように説明する方が簡単かもしれません。

if( boolean_expression_1 ) {
  statement_1;
  return;
}

if( boolean_expression_2 ) {
  statement_2;
  return;
}

default_statement;
return;

上記の例は、学校で一般的に教えられていることを破っていますが、早期に戻ること多く、スタックベースのvmと同じくらい高速で読みやすい場合があります。

プリミティブのスイッチを最適化する必要があるため、どのブロックを使用して制御するかは、比較対象に基づいて選択する必要があります。

長いswitchand ifステートメントは非常に冗長になり、維持が困難になる傾向があり、さらに多くの条件をチェックする必要があるため、パフォーマンスが低下することに注意してください。

Hash多くの条件を持つ長い制御ブロックの代わりに、匿名のクラス/関数またはコマンドパターンを検討する必要がある場合があります。

ハッシュとコマンドパターンにより、コードの実行速度が向上し、コードの保守性が向上します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.