Альтернатива инструкции goto в Java

Что такое альтернативная функция для ключевого слова goto в Java?

Так как Java не имеет goto.

Ответы

Ответ 1

Вы можете использовать обозначенный 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.

Ответ 2

В Java нет прямого эквивалента концепции goto. Есть несколько конструкций, которые позволяют вам делать некоторые из вещей, которые вы можете сделать с классическим goto.

  • Операторы break и continue позволяют вам выпрыгивать из блока в операторе цикла или switch.
  • Обозначенная инструкция и break <label> позволяют вам выпрыгивать из произвольного составного оператора на любой уровень в пределах данного метода (или блока инициализации).
  • Если вы помечаете оператор цикла, вы можете continue <label> продолжить следующую итерацию внешнего цикла из внутреннего цикла.
  • Бросание и перехватывание исключений позволяет вам (эффективно) выпрыгнуть из многих уровней вызова метода. (Однако исключения относительно дороги и считаются плохим способом "обычного" потока управления 1.)
  • И, конечно, есть return.

Ни одна из этих конструкций Java не позволяет вам отложить назад или в точку кода на том же уровне вложенности, что и текущая инструкция. Все они выпрыгивают из одного или нескольких уровней гнездования (охвата), и все они (кроме continue) прыгают вниз. Это ограничение помогает избежать синдрома goto "спагетти код", присущего старому BASIC, FORTRAN и кобулу 2.


1- Самая дорогая часть исключений - это фактическое создание объекта исключения и его stacktrace. Если вам действительно нужно использовать обработку исключений для "нормального" управления потоком, вы можете либо предварительно распределить/повторно использовать объект исключения, либо создать собственный класс исключений, который переопределяет метод fillInStackTrace(). Недостатком является то, что методы исключений printStackTrace() не дадут вам полезной информации... если вам когда-нибудь понадобится их называть.

2 - Синдром кода спагетти породил метод структурированного программирования, где вы ограничили использование доступных языковых конструкций. Это можно применить к BASIC, Fortran и COBOL, но это требовало ухода и дисциплины. Избавление от goto полностью было прагматически лучшим решением. Если вы держите его на языке, всегда есть клоун, который будет злоупотреблять им.

Ответ 3

Просто для удовольствия здесь - это реализация GOTO на Java.

Пример:

   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!

Нужно ли добавлять "не использовать его!"?

Ответ 4

Хотя некоторые комментаторы и downvoters утверждают, что это не goto, сгенерированный байт-код из приведенных ниже инструкций Java действительно предполагает, что эти инструкции действительно выражают семантику goto.

В частности, цикл 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  ..

Ответ 5

Если вы действительно хотите что-то вроде операторов goto, вы всегда можете попытаться взломать именованные блоки.

Вы должны попасть в область действия блока, чтобы разбить на метку:

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

Я не буду лекцию о том, почему вы должны избегать goto - я предполагаю, что вы уже знаете ответ на этот вопрос.

Ответ 6

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

Ответ 7

StephenC пишет:

Есть две конструкции, которые позволяют вам делать некоторые вещи, которые вы может сделать с классической goto.

Еще один...

Мэтт Вулф пишет:

Люди всегда говорят о том, чтобы никогда не использовать 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

Блок finally всегда выполняется, когда блок try завершается. Эта гарантирует, что блок finally будет выполнен, даже если неожиданное исключение. Но, наконец, полезно не только для исключения обработка - это позволяет программисту избежать кода очистки случайно обходится возвратом, продолжается или прерывается. Помещение очистки код в блоке finally всегда является хорошей практикой, даже если нет исключения ожидаются.

Глупый вопрос интервью, связанный с последним, заключается в следующем: если вы вернетесь из блока try {}, но имеете и возврат в свой finally {} тоже, какое значение возвращается?

Ответ 8

Попробуйте выполнить приведенный ниже код. Это работает для меня.

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 2
            iCountTaksa = 2;
            break  LabelEndTaksa_Exit;
        }

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

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

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

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

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

        if (iCountTaksa == 8) { //If count is 8 then next it 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++) {"

Ответ 9

Самый простой способ:

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

Ответ 10

Используйте помеченный помехой как альтернативу goto.

Ответ 11

Java не имеет goto, потому что он делает код неструктурированным и нечетким для чтения. Однако вы можете использовать break и continue как цивилизованную форму goto без проблем.


Прыжки вперед с использованием break -

ahead: {
    System.out.println("Before break");
    break ahead;
    System.out.println("After Break"); // This won't execute
}
// After a line break ahead, the code flow starts from here, after the ahead block
System.out.println("After ahead");

Выход

Before Break
After ahead

Прыжки назад с использованием continue

before: {
    System.out.println("Continue");
    continue before;
}

Это приведет к бесконечному циклу, так как каждый раз, когда выполняется строка continue before, поток кода снова начнется с before.