web-dev-qa-db-ja.com

Javaのgotoステートメントの代替

Javaのgotoキーワードの代替機能は何ですか?

Javaにはgotoがないため。

83
gmhk

ラベル付きの BREAK ステートメントを使用できます。

search:
    for (i = 0; i < arrayOfInts.length; i++) {
        for (j = 0; j < arrayOfInts[i].length; j++) {
            if (arrayOfInts[i][j] == searchfor) {
                foundIt = true;
                break search;
            }
        }
    }

ただし、適切に設計されたコードでは、GOTO機能は必要ありません。

82
Padmarag

Javaのgotoコンセプトに直接相当するものはありません。古典的なgotoでできることのいくつかをいくつかのできるコンストラクトがあります。

  • breakおよびcontinueステートメントを使用すると、ループまたはスイッチステートメントでブロックから飛び出すことができます。
  • ラベル付きステートメントとbreak <label>を使用すると、任意の複合ステートメントから特定のメソッド(または初期化ブロック)内の任意のレベルにジャンプできます。
  • ループ文にラベルを付けると、continue <label>を使用して、内側のループから外側のループの次の反復を続行できます。
  • 例外をスローしてキャッチすると、メソッド呼び出しの多くのレベルから(効果的に)ジャンプすることができます。 (ただし、例外は比較的高価であり、「通常の」制御フローを行うには悪い方法と見なされます1
  • そしてもちろん、returnがあります。

これらのJava構造体のいずれも、現在のステートメントと同じレベルの入れ子にあるコード内のポイントまたは後方への分岐を許可しません。それらはすべて、1つ以上のネスト(スコープ)レベルを飛び出し、すべて(continueを除く)下方にジャンプします。この制限は、古いBASIC、FORTRAN、およびCOBOLコードに固有のgoto「スパゲッティコード」症候群を回避するのに役立ちます2


1-例外の最も高価な部分は、例外オブジェクトとそのスタックトレースの実際の作成です。 「通常の」フロー制御に本当に本当に例外処理を使用する必要がある場合は、例外オブジェクトを事前に割り当て/再利用するか、fillInStackTrace()メソッドをオーバーライドするカスタム例外クラスを作成できます。欠点は、例外のprintStackTrace()メソッドでは有用な情報が得られないことです...呼び出す必要がある場合です。

2-スパゲッティコードシンドロームは、利用可能な言語構成要素の使用を制限する 構造化プログラミング アプローチを生み出しました。これは BASICFortran および COBOL に適用できますが、注意と訓練が必要です。 gotoを完全に削除することは、実用的に優れたソリューションでした。あなたが言語でそれを保持する場合、それを乱用するピエロが常に存在します。

41
Stephen C

楽しみのために、 here はJavaのGOTO実装です。

例:

   1 public class GotoDemo {
   2     public static void main(String[] args) {
   3         int i = 3;
   4         System.out.println(i);
   5         i = i - 1;
   6         if (i >= 0) {
   7             GotoFactory.getSharedInstance().getGoto().go(4);
   8         }
   9         
  10         try {
  11             System.out.print("Hell");
  12             if (Math.random() > 0) throw new Exception();            
  13             System.out.println("World!");
  14         } catch (Exception e) {
  15             System.out.print("o ");
  16             GotoFactory.getSharedInstance().getGoto().go(13);
  17         }
  18     }
  19 }

実行する:

$ Java -cp bin:asm-3.1.jar GotoClassLoader GotoDemo           
   3
   2
   1
   0
   Hello World!

「使用しないでください!」を追加する必要がありますか?

29
Pascal Thivent

これはgotoではないという意見もありますが、以下のJavaステートメントから生成されたバイトコードは、これらのステートメントが本当にgotoを表現していることを示唆しています。セマンティクス。

具体的には、2番目の例のdo {...} while(true);ループは、ループ条件を評価しないようにJavaコンパイラーによって最適化されます。

前進する

label: {
  // do stuff
  if (check) break label;
  // do more stuff
}

バイトコード内:

2  iload_1 [check]
3  ifeq 6          // Jumping forward
6  ..

後方ジャンプ

label: do {
  // do stuff
  if (check) continue label;
  // do more stuff
  break label;
} while(true);

バイトコード内:

 2  iload_1 [check]
 3  ifeq 9
 6  goto 2          // Jumping backward
 9  ..
17
Lukas Eder

Gotoステートメントのようなものが本当に必要な場合は、常に名前付きブロックに分割してみてください。

ラベルに到達するには、ブロックのスコープ内にいる必要があります。

namedBlock: {
  if (j==2) {
    // this will take you to the label above
    break namedBlock;
  }
}

Gotoを避けるべき理由については説明しません。その答えはすでにわかっていると思います。

5
Amir Afghani
public class TestLabel {

    enum Label{LABEL1, LABEL2, LABEL3, LABEL4}

    /**
     * @param args
     */
    public static void main(String[] args) {

        Label label = Label.LABEL1;

        while(true) {
            switch(label){
                case LABEL1:
                    print(label);

                case LABEL2:
                    print(label);
                    label = Label.LABEL4;
                    continue;

                case LABEL3:
                    print(label);
                    label = Label.LABEL1;
                    break;

                case LABEL4:
                    print(label);
                    label = Label.LABEL3;
                    continue;
            }
            break;
        }
    }

    public final static void print(Label label){
        System.out.println(label);
    }
4
code lover

StephenCの書き込み:

古典的なgotoでできることのいくつかを実行できるようにする2つの構造があります。

もう1つ...

マット・ウルフはこう書いている:

人々はいつもgotoを使用しないことについて常に話しますが、かなりよく知られ使用されている本当に良い実世界のユースケースがあると思います。ロックかどうかはわかりませんが、私の場合は、必須のクリーンアップを実行できるように、戻る直前に休憩にジャンプできるようにしたいです。

try {
    // do stuff
    return result;  // or break, etc.
}
finally {
    // clean up before actually returning, even though the order looks wrong.
}

http://docs.Oracle.com/javase/tutorial/essential/exceptions/finally.html

Tryブロックが終了すると、finallyブロックは常に実行されます。これにより、予期しない例外が発生した場合でも、finallyブロックが実行されます。しかし最終的には、例外処理だけでなく、プログラマーがリターン、続行、またはブレークによって誤ってクリーンアップコードをバイパスすることを回避できます。例外が予想されない場合でも、finallyブロックにクリーンアップコードを配置することは常に良い習慣です。

Finallyに関連する愚かなインタビューの質問は、try {}ブロックから戻ったが、finally {}にも戻りがある場合、どの値が返されますか?

3
android.weasel

最も簡単なのは:

int label = 0;
loop:while(true) {
    switch(state) {
        case 0:
            // Some code
            state = 5;
            break;

        case 2:
            // Some code
            state = 4;
            break;
        ...
        default:
            break loop;
    }
}
1
ratchet freak

以下のコードを試してください。わたしにはできる。

for (int iTaksa = 1; iTaksa <=8; iTaksa++) { // 'Count 8 Loop is  8 Taksa

    strTaksaStringStar[iCountTaksa] = strTaksaStringCount[iTaksa];

    LabelEndTaksa_Exit : {
        if (iCountTaksa == 1) { //If count is 6 then next it's 2
            iCountTaksa = 2;
            break  LabelEndTaksa_Exit;
        }

        if (iCountTaksa == 2) { //If count is 2 then next it's 3
            iCountTaksa = 3;
            break  LabelEndTaksa_Exit;
        }

        if (iCountTaksa == 3) { //If count is 3 then next it's 4
            iCountTaksa = 4;
            break  LabelEndTaksa_Exit;
        }

        if (iCountTaksa == 4) { //If count is 4 then next it's 7
            iCountTaksa = 7;
            break  LabelEndTaksa_Exit;
        }

        if (iCountTaksa == 7) { //If count is 7 then next it's 5
            iCountTaksa = 5;
            break  LabelEndTaksa_Exit;
        }

        if (iCountTaksa == 5) { //If count is 5 then next it's 8
            iCountTaksa = 8;
            break  LabelEndTaksa_Exit;
        }

        if (iCountTaksa == 8) { //If count is 8 then next it's 6
            iCountTaksa = 6;
            break  LabelEndTaksa_Exit;
        }

        if (iCountTaksa == 6) { //If count is 6 then loop 1  as 1 2 3 4 7 5 8 6  --> 1
            iCountTaksa = 1;
            break  LabelEndTaksa_Exit;
        }
    }   //LabelEndTaksa_Exit : {

} // "for (int iTaksa = 1; iTaksa <=8; iTaksa++) {"
0
mahasam