@harigm: Вы можете привести пример кода, который вы бы написали, еслиgoto он доступен на Java? Я думаю, что в этом заключается более важный вопрос.
polygenelubricants
3
@harigm: я второй полиген, не могли бы вы обновить свой вопрос, чтобы указать, почему вашей программе нужен goto?
Все
13
Люди всегда говорят о том, чтобы никогда не использовать goto, но я думаю, что есть действительно хороший пример использования в реальном мире, который довольно хорошо известен и используется ... То есть, убедитесь, что вы выполнили некоторый код перед возвратом из функции ... Обычно его освобождение замки или что-то еще, но в моем случае я бы хотел иметь возможность прыгнуть на перерыв прямо перед возвращением, чтобы я мог выполнить требуемую обязательную очистку. Конечно, программа, заваленная повсюду goto, была бы ужасной, но если ограничиваться телами методов, это не кажется таким уж плохим, если вы следуете соглашению (только переходите к концу функций, никогда не выполняйте резервное копирование)
Мэтт Wolfe
7
Вы в хорошей компании. Линус Торвальдс страстно защищал goto kerneltrap.org/node/553 . Несомненно, самое заметное упущение в Project Coin.
Флетч
7
@MattWolfe не пытается-наконец выполнить свою работу в этом примере?
Почему вам не нужны функции goto в правильно разработанном коде?
rogermushroom
13
Потому что только ассемблер может его использовать. Операторы while, for, do-while, foreach, вызовы функции - все это операторы GOTO, используемые управляемым и предсказуемым образом. На уровне ассемблера это всегда будут GOTO, но вам не нужны функциональные возможности, которые дает чистый GOTO - его единственное преимущество перед функциями и операторами цикла / управления состоит в том, что он позволяет вам переходить в середину любого кода в любом месте. . И это «преимущество» само по себе является определением «спагетти-кода».
1
@whatsthebeef Вот знаменитое письмо Эдсгера В. Дейкстры 1968 года, в котором объясняется, почему он считал goto вредным .
Нет прямого эквивалента goto Java концепции. Есть несколько конструкций, которые позволяют вам делать то же, что и с классикой goto.
Операторы breakи continueпозволяют выйти из блока в цикле или операторе переключения.
Помеченный оператор, break <label>позволяющий перейти из произвольного составного оператора на любой уровень в рамках данного метода (или блока инициализатора).
Если вы пометите оператор цикла, вы можете continue <label>продолжить следующую итерацию внешнего цикла из внутреннего цикла.
Создание и перехват исключений позволяет (эффективно) выпрыгивать из многих уровней вызова метода. (Однако исключения являются относительно дорогими и считаются плохим способом выполнения «обычного» потока управления 1. )
И, конечно, есть return.
Ни одна из этих конструкций Java не позволяет выполнить переход назад или к точке кода на том же уровне вложенности, что и текущий оператор. Все они выпрыгивают из одного или нескольких уровней вложенности (области действия), и все (кроме continue) прыгают вниз. Это ограничение помогает избежать синдрома «спагетти-кода» goto, присущего старым кодам BASIC, FORTRAN и COBOL 2 .
1- Самая дорогая часть исключений - это фактическое создание объекта исключения и его трассировки стека. Если вам действительно действительно нужно использовать обработку исключений для «нормального» управления потоком, вы можете либо предварительно выделить / повторно использовать объект исключения, либо создать собственный класс исключения, который переопределяет fillInStackTrace()метод. Обратной стороной является то, что исключениеprintStackTrace() методы не дадут вам полезной информации ... если вам когда-нибудь понадобится их вызвать.
2. Синдром спагетти-кода породил подход структурированного программирования , при котором вы ограничиваете использование доступных языковых конструкций. Это можно было применить к BASIC , Fortran и COBOL , но это требовало осторожности и дисциплины. Полное избавление от этого gotoбыло прагматически лучшим решением. Если вы сохраните это на языке, всегда найдется какой-нибудь клоун, который будет злоупотреблять этим.
Конструкции цикла, такие как while (...) {} и for (...) {}, позволяют повторять блоки кода без явного перехода в произвольное место. Кроме того, вызовы метода myMethod () позволяют выполнять код, найденный в другом месте, и возвращаться к текущему блоку по завершении. Все это можно использовать для замены функциональности goto , предотвращая при этом общую проблему невозможности возврата, которую позволяет goto.
Крис Нава,
@Chris - это правда, но большинство языков, поддерживающих GOTO, также имеют более близкие аналоги конструкциям цикла Java.
Stephen C
1
@Chris - классический FORTRAN имеет циклы for, а классический COBOL также имеет циклические конструкции (хотя я не могу вспомнить детали). Только классический BASIC не имеет явных циклических конструкций ...
Ошибка: Math.random()может возвращать 0. Должно быть> =
poitroae
Да хорошо. Все, что может быть реализовано только с помощью взлома байт-кода, на самом деле не является Java ...
Стивен К.
Есть ли что-то подобное, что поддерживает метки вместо номеров строк?
Behrouz.M
1
Ссылка на реализацию не работает.
LarsH
@poitroae Это забавное пасхальное яйцо, которое кто-то найдет HellWorld!o World!выходом и придет в замешательство. #AllBugsAreFeatures
ReinstateMonica3167040
18
Хотя некоторые комментаторы и отрицательные голоса утверждают, что это не goto , сгенерированный байт-код из приведенных ниже операторов Java действительно предполагает, что эти операторы действительно выражают семантику goto .
В частности, do {...} while(true);цикл во втором примере оптимизирован компиляторами Java, чтобы не оценивать условие цикла.
Прыжок вперед
label: {
// do stuffif (check) break label;
// do more stuff
}
В байт-коде:
2 iload_1 [check]
3 ifeq 6// Jumping forward6 ..
Прыжок назад
label: do {
// do stuffif (check) continue label;
// do more stuffbreak label;
} while(true);
Как do / while прыгает назад? Он все равно просто вылезает из блока. Пример счетчика: label: do {System.out.println ("Backward"); метка продолжения;} while (false); Я думаю, что в вашем примере while (true) - это то, что отвечает за прыжок назад.
Бен Холланд
@BenHolland: continue labelпрыжок назад
Лукас Эдер
Я все еще не уверен. Оператор continue пропускает текущую итерацию цикла for, while или do-while. Продолжение переходит к концу тела цикла, которое затем оценивается для логического выражения, управляющего циклом. Время - это то, что прыгает назад, а не продолжение. См. Docs.oracle.com/javase/tutorial/java/nutsandbolts/branch.html
Бен Холланд,
@BenHolland: Технически ты прав. С логической точки зрения, если // do stuffи // do more stuffявляются интересующими утверждениями, continue label"имеет эффект" прыжка назад ( while(true)конечно, из-за утверждения). Я не знал, что это был такой точный вопрос ...
Лукас Эдер
2
@BenHolland: Я обновил ответ. Преобразуется while(true)компилятором в gotoоперацию байт-кода. Как trueпостоянный литерал, компилятор может выполнять эту оптимизацию и не должен ничего оценивать. Итак, мой пример действительно - это goto, прыжок назад ...
Лукас Эдер
5
Если вы действительно хотите что-то вроде операторов goto, вы всегда можете попробовать разбить на именованные блоки.
Вы должны находиться в рамках блока, чтобы перейти к метке:
namedBlock: {
if (j==2) {
// this will take you to the label abovebreak namedBlock;
}
}
Я не буду читать вам лекцию о том, почему вам следует избегать goto - я предполагаю, что вы уже знаете ответ на этот вопрос.
Я попытался реализовать это в своем вопросе SO, который связан здесь . На самом деле это не приведет вас к «метке выше», возможно, я неверно истолковал утверждения автора, но для ясности добавлю, что это приведет вас к концу внешнего блока («помеченный» блок), который находится ниже где ты ломаешься. Следовательно, вы не можете «сломаться» вверх. По крайней мере, я так понимаю.
Это приведет к исключению StackOverFlowException, если вы запустите его достаточно долго, поэтому мне нужно перейти.
Кевин Паркер
3
@Kevin: Как это приведет к переполнению стека? В этом алгоритме нет рекурсии ...
Лукас Эдер
1
Это очень похоже на исходное доказательство того, что любую программу можно написать без использования "goto" - превратив его в цикл while с переменной "label", которая в десять раз хуже, чем любой goto.
gnasher729
3
StephenC пишет:
Есть две конструкции, которые позволяют вам делать некоторые из вещей, которые вы можете делать с классическим goto.
Еще один...
Мэтт Вулф пишет:
Люди всегда говорят о том, чтобы никогда не использовать goto, но я думаю, что есть действительно хороший пример использования в реальном мире, который довольно хорошо известен и используется ... То есть, убедитесь, что вы выполнили некоторый код перед возвратом из функции ... Обычно его освобождение замки или что-то еще, но в моем случае я бы хотел иметь возможность прыгнуть на перерыв прямо перед возвратом, чтобы я мог выполнить требуемую обязательную очистку.
try {
// do stuffreturn result; // or break, etc.
}
finally {
// clean up before actually returning, even though the order looks wrong.
}
Блок finally всегда выполняется при выходе из блока try. Это гарантирует выполнение блока finally даже в случае возникновения непредвиденного исключения. Но наконец, он полезен не только для обработки исключений - он позволяет программисту избежать случайного обхода кода очистки посредством возврата, продолжения или прерывания. Помещение кода очистки в блок finally всегда является хорошей практикой, даже если не ожидается никаких исключений.
Глупый вопрос на собеседовании, связанный с finally, звучит так: если вы вернетесь из блока try {}, но также получите результат в своем finally {}, какое значение будет возвращено?
Я не согласен с тем, что это глупый вопрос для интервью. Опытный Java-программист должен знать, что происходит, хотя бы для того, чтобы понять, почему вставлять returnв finallyблок - плохая идея. (И даже если знание не является строго необходимым, я бы побеспокоился о программисте, у которого не было бы любопытства узнать ...)
Стивен С.
1
Самый простой:
int label = 0;
loop:while(true) {
switch(state) {
case0:
// Some code
state = 5;
break;
case2:
// Some code
state = 4;
break;
...
default:
break loop;
}
}
В Java этого нет goto, потому что он делает код неструктурированным и нечетким для чтения. Однако вы можете использовать breakи continueкак цивилизованную форму goto без проблем.
Прыжок вперед с перерывом -
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");
Ваш пример прыжка назад с использованием continue неверен. Вы не можете использовать "continue" вне тела цикла, это вызовет ошибку компиляции. Однако внутри цикла continue просто выполняет переход по условию цикла. Таким образом, что-то вроде while (true) {continue;} будет бесконечным циклом, как и while (true) {} в этом отношении.
goto
он доступен на Java? Я думаю, что в этом заключается более важный вопрос.Ответы:
Вы можете использовать пометку 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 не требуется.
источник
Нет прямого эквивалента
goto
Java концепции. Есть несколько конструкций, которые позволяют вам делать то же, что и с классикойgoto
.break
иcontinue
позволяют выйти из блока в цикле или операторе переключения.break <label>
позволяющий перейти из произвольного составного оператора на любой уровень в рамках данного метода (или блока инициализатора).continue <label>
продолжить следующую итерацию внешнего цикла из внутреннего цикла.return
.Ни одна из этих конструкций Java не позволяет выполнить переход назад или к точке кода на том же уровне вложенности, что и текущий оператор. Все они выпрыгивают из одного или нескольких уровней вложенности (области действия), и все (кроме
continue
) прыгают вниз. Это ограничение помогает избежать синдрома «спагетти-кода» goto, присущего старым кодам BASIC, FORTRAN и COBOL 2 .1- Самая дорогая часть исключений - это фактическое создание объекта исключения и его трассировки стека. Если вам действительно действительно нужно использовать обработку исключений для «нормального» управления потоком, вы можете либо предварительно выделить / повторно использовать объект исключения, либо создать собственный класс исключения, который переопределяет
fillInStackTrace()
метод. Обратной стороной является то, что исключениеprintStackTrace()
методы не дадут вам полезной информации ... если вам когда-нибудь понадобится их вызвать.2. Синдром спагетти-кода породил подход структурированного программирования , при котором вы ограничиваете использование доступных языковых конструкций. Это можно было применить к BASIC , Fortran и COBOL , но это требовало осторожности и дисциплины. Полное избавление от этого
goto
было прагматически лучшим решением. Если вы сохраните это на языке, всегда найдется какой-нибудь клоун, который будет злоупотреблять этим.источник
Ради удовольствия, вот реализация GOTO на Java.
Нужно ли мне добавлять «не использовать!»?
источник
Math.random()
может возвращать 0. Должно быть> =HellWorld!o World!
выходом и придет в замешательство. #AllBugsAreFeaturesХотя некоторые комментаторы и отрицательные голоса утверждают, что это не 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 ..
источник
continue label
прыжок назад// do stuff
и// do more stuff
являются интересующими утверждениями,continue label
"имеет эффект" прыжка назад (while(true)
конечно, из-за утверждения). Я не знал, что это был такой точный вопрос ...while(true)
компилятором вgoto
операцию байт-кода. Какtrue
постоянный литерал, компилятор может выполнять эту оптимизацию и не должен ничего оценивать. Итак, мой пример действительно - это goto, прыжок назад ...Если вы действительно хотите что-то вроде операторов goto, вы всегда можете попробовать разбить на именованные блоки.
Вы должны находиться в рамках блока, чтобы перейти к метке:
namedBlock: { if (j==2) { // this will take you to the label above break namedBlock; } }
Я не буду читать вам лекцию о том, почему вам следует избегать goto - я предполагаю, что вы уже знаете ответ на этот вопрос.
источник
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); }
источник
StephenC пишет:
Еще один...
Мэтт Вулф пишет:
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 {}, какое значение будет возвращено?
источник
return
вfinally
блок - плохая идея. (И даже если знание не является строго необходимым, я бы побеспокоился о программисте, у которого не было бы любопытства узнать ...)Самый простой:
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; } }
источник
Попробуйте приведенный ниже код. Меня устраивает.
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++) {"
источник
Используйте разрыв с пометкой как альтернативу goto.
источник
В Java этого нет
goto
, потому что он делает код неструктурированным и нечетким для чтения. Однако вы можете использоватьbreak
иcontinue
как цивилизованную форму goto без проблем.Прыжок вперед с перерывом -
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");
Выход :
Переход назад с помощью continue
before: { System.out.println("Continue"); continue before; }
Это приведет к бесконечной петле , как каждый раз , когда линия
continue before
выполнена, поток кода будет снова начать сbefore
.источник