Альтернатива инструкции 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
.