Это плохая практика использовать break для выхода из цикла в Java? [закрытый]
мне было интересно, если это "плохая практика", чтобы использовать break оператор для выхода из цикла вместо выполнения условия цикла?
У меня недостаточно понимания в Java и JVM, чтобы знать, как обрабатывается цикл, поэтому мне было интересно, не упускаю ли я что-то критическое, делая это.
фокус этого вопроса: есть ли определенные накладные расходы на производительность?
13 ответов:
Господи, нет. Иногда существует вероятность того, что в цикле может произойти что-то, что удовлетворяет общему требованию, не удовлетворяя условию логического цикла. В таком случае,
breakиспользуется, чтобы остановить вас на велосипеде вокруг петли неостроумно.пример
String item; for(int x = 0; x < 10; x++) { // Linear search. if(array[x].equals("Item I am looking for")) { //you've found the item. Let's stop. item = array[x]; break; } }что имеет больше смысла в этом примере. Продолжайте цикл до 10 каждый раз, даже после того, как вы его нашли, или цикл, пока не найдете элемент и не остановитесь? Или положить его в условия реального мира; когда вы находите свои ключи, вы продолжаете искать?
редактировать в ответ на комментарий
почему бы не установить
xдо11разорвать петлю? Это бессмысленно. У нас естьbreak! Если только ваш код не делает предположение, чтоx- это определенно больше, чем10позже (и это, вероятно, не должно быть), то ты в порядке, просто используяbreak.редактировать для полноты картины
есть определенно другие способы имитации
break. Например, добавление дополнительной логики к условию завершения в цикле. Говоря, что это либо цикл бессмысленно или использоватьbreakнечестно. Как уже отмечалось, цикл while часто может достигать аналогичной функциональности. Например, следуя приведенному выше примеру..while(x < 10 && item == null) { if(array[x].equals("Item I am looking for")) { item = array[x]; } x++; }используя
breakпросто означает, что вы можете достичь этой функциональности сforпетли. Это также означает, что вы не должны держать добавление условий in в логику завершения, когда вы хотите, чтобы цикл вел себя по-другому. Например.for(int x = 0; x < 10; x++) { if(array[x].equals("Something that will make me want to cancel")) { break; } else if(array[x].equals("Something else that will make me want to cancel")) { break; } else if(array[x].equals("This is what I want")) { item = array[x]; } }, а не
while loopс условием завершения, которое выглядит следующим образом:while(x < 10 && !array[x].equals("Something that will make me want to cancel") && !array[x].equals("Something else that will make me want to cancel"))
используя
break, как и практически любой другой язык можете быть плохой практикой, в определенном контексте, где вы явно злоупотребляете им. Но некоторые очень важные идиомы не могут быть закодированы без него или, по крайней мере, приведут к гораздо менее читаемому коду. В таких случаяхbreak- Это путь.другими словами, не слушайте никаких общих, неквалифицированных советов-о
breakили что-нибудь еще. Это не один раз, что я видел код полностью истощена просто чтобы буквально обеспечить соблюдение "хорошей практики".Что касается вашего беспокойства о накладных расходах на производительность, то их абсолютно нет. На уровне байт-кода все равно нет явных петлевых конструкций: все управление потоком реализовано в терминах условных скачков.
JLS указывает, что разрыв является ненормальным завершением цикла. Однако только потому, что он считается ненормальным, не означает, что он не используется во многих различных примерах кода, проектах, продуктах, космических челноках и т. д. Спецификация JVM не указывает ни на существование, ни на отсутствие потери производительности, хотя ясно, что выполнение кода будет продолжаться после цикла.
однако, читаемость кода может пострадать с нечетными перерывами. Если вы вставляете перерыв в комплекс, если оператор, окруженный побочными эффектами и нечетным кодом очистки, с возможным многоуровневым разрывом с меткой(или, что еще хуже, со странным набором условий выхода один за другим), это не будет легко читать для всех.
Если вы хотите разорвать свой цикл, заставив переменную итерации выйти за пределы диапазона итераций или иным образом введя не обязательно прямой способ выхода, он менее читаем, чем
break.однако, зацикливание дополнительных раз в пустой образ - это почти всегда плохая практика, поскольку она требует дополнительных итераций и может быть неясной.
по-моему a
Forцикл должен использоваться, когда фиксированное количество итераций будет сделано, и они не будут остановлены до завершения каждой итерации. В другом случае, когда вы хотите выйти раньше, я предпочитаю использоватьWhileпетли. Даже если вы читали эти два маленьких слова, это кажется более логичным. Некоторые примеры:for (int i=0;i<10;i++) { System.out.println(i); }когда я быстро прочитаю этот код, я буду точно знать, что он распечатает 10 строк, а затем продолжит.
for (int i=0;i<10;i++) { if (someCondition) break; System.out.println(i); }Это уже менее ясно для меня. Почему бы вам сначала заявить, что вы возьмете 10 итераций, но затем внутри цикла добавьте некоторые дополнительные условия, чтобы остановить раньше?
Я предпочитаю предыдущий пример, написанный таким образом (даже когда он немного более подробный, но это только с 1 строкой больше):
int i=0; while (i<10 && !someCondition) { System.out.println(i); i++; }каждый, кто прочитает этот код, сразу увидит, что есть дополнительное условие, которое может завершить цикл раньше.
конечно, в очень маленьких петлях вы всегда можете обсудите, что каждый программист заметит оператор break. Но я могу сказать по своему собственному опыту, что в больших петлях эти разрывы можно контролировать. (И это подводит нас к другой теме, чтобы начать разбивать код на более мелкие куски)
использование break in loops может быть совершенно законным, и это может быть даже единственным способом решить некоторые проблемы.
тем не менее, это плохая репутация исходит из того, что новые программисты обычно злоупотребляют им, что приводит к путанице кода, особенно с помощью break, чтобы остановить цикл в условиях, которые могли бы быть написаны в заявлении условия цикла в первую очередь.
нет, это не плохая практика, чтобы вырваться из петли, когда если достигнуто определенное желаемое состояние(как совпадения). Много раз вы можете остановить итерации, потому что вы уже достигли того, что хотите, и нет смысла повторять дальше. Но, будьте осторожны, чтобы убедиться, что вы случайно не пропустили что-то или вспыхивая, когда это не требуется.
Это также может добавить к повышению производительности Если вы нарушите цикл, вместо этого итерации по тысячам записей, даже если цель цикла завершена(т. е. может быть, чтобы соответствовать требуемой записи уже сделано).
пример :
for (int j = 0; j < type.size(); j++) { if (condition) { // do stuff after which you want break; // stop further iteration } }
это не плохая практика, но это может сделать код менее читабельным. Один полезный рефакторинг, чтобы обойти это, - переместить цикл в отдельный метод, а затем использовать оператор return вместо разрыва, например это (пример поднят из ответа @Chris):
String item; for(int x = 0; x < 10; x++) { // Linear search. if(array[x].equals("Item I am looking for")) { //you've found the item. Let's stop. item = array[x]; break; } }может быть рефакторинг (с помощью извлечение метода) для этого:
public String searchForItem(String itemIamLookingFor) { for(int x = 0; x < 10; x++) { if(array[x].equals(itemIamLookingFor)) { return array[x]; } } }при вызове из окружающего кода может оказаться более читаемым.
если вы начинаете делать что-то вроде этого, то я бы сказал, что это начинает становиться немного странным, и вам лучше переместить его в отдельный метод, который
returnsрезультат на matchedCondition.boolean matched = false; for(int i = 0; i < 10; i++) { for(int j = 0; j < 10; j++) { if(matchedCondition) { matched = true; break; } } if(matched) { break; } }рассказать о том, как очистить приведенный выше код, вы можете выполнить рефакторинг, переместив код в функцию, которая
returnsвместоbreaks. Это в общем, лучше иметь дело со сложным / грязнымbreaks.public boolean matches() for(int i = 0; i < 10; i++) { for(int j = 0; j < 10; j++) { if(matchedCondition) { return true; } } } return false; }однако для чего-то простого, как мой ниже приведен пример. Обязательно используйте
break!for(int i = 0; i < 10; i++) { if(wereDoneHere()) { // we're done, break. break; } }и изменение условий, в приведенном выше случае
iи , вы бы просто сделать код очень трудно читать. Также может быть случай, когда верхние пределы (10 в Примере) являются переменными, поэтому было бы еще сложнее угадать, какое значение установить, чтобы выйти из цикла. Вы могли бы, конечно, просто установитьiиjк целому числу.MAX_VALUE, но я думаю, вы можете видеть, что это начинает становиться грязным очень быстро. :)
Существует ряд распространенных ситуаций, на которые
break- Это самый естественный способ выражения алгоритма. Они называются конструкциями "петля с половиной"; пример парадигмыwhile (true) { item = stream.next(); if (item == EOF) break; process(item); }если вы не можете использовать
breakдля этого вы должны повторить себя вместо этого:item = stream.next(); while (item != EOF) { process(item); item = stream.next(); }общепризнано, что это еще хуже.
аналогично для
continue, есть общий шаблон, который выглядит так:for (item in list) { if (ignore_p(item)) continue; if (trivial_p(item)) { process_trivial(item); continue; } process_complicated(item); }этот часто более читаемый, чем альтернатива с цепью
else if, особенноprocess_complicatedэто больше, чем просто один вызов функции.читайте далее: выходы из цикла и структурированное Программирование: Возобновление дебатов
в то время как его не плохая практика использовать перерыв и есть много отличных применений для него, это не должно быть все, на что вы полагаетесь. Почти любое использование разрыва может быть записано в условие цикла. Код гораздо более читаем, когда используются реальные условия, но в случае длительного или бесконечного цикла перерывы имеют смысл. Они тоже имеют смысл при поиске данных, как показано выше.
если вы заранее знаете, где цикл должен будет остановиться, это, вероятно, улучшит читаемость кода, чтобы указать условие в
for,whileили`do-whileпетли.в противном случае, это точный случай использования для
break.
breakиcontinueнарушает читаемость для читателя, хотя это часто полезно. Не так много, как концепция "Гото", но почти.кроме того, если вы возьмете некоторые новые языки, такие как Scala (вдохновленные Java и функциональными языками программирования, такими как Ocaml), вы заметите, что
breakиcontinueпросто исчезли.особенно в функциональном программировании, этот стиль кода избегать:
почему scala не поддерживает break и продолжать?
подведем итоги:
breakиcontinueшироко используются в Java для императивного стиля, но для любых кодеров, которые используются для практики функционального программирования, это может быть.. странный.
Comments