Сегодня у меня был коллега, который предложил мне реорганизовать мой код, чтобы использовать оператор метки для управления потоком через 2 вложенных цикла for, которые я создал. Я никогда не использовал их раньше, потому что лично считаю, что они ухудшают читаемость программы. Однако я готов передумать об их использовании, если аргумент достаточно веский. Что люди думают о заявлениях на этикетках?
(Поскольку вы можете помещать циклы в методы, это полностью эквивалентно одиночному / множественному / раннему выходу из методов.)




Мне любопытно узнать, какая у вас альтернатива лейблам. Я думаю, что это в значительной степени сводится к аргументу «вернуть как можно раньше» или «использовать переменную для хранения возвращаемого значения и вернуть только в конце».
Ярлыки довольно стандартные, когда у вас есть вложенные циклы. Единственный способ, которым они действительно ухудшают читабельность, - это когда другой разработчик никогда их раньше не видел и не понимает, что они означают.
Рекурсивный подход. Или вы могли бы условно сломаться, если бы (нашли) обрыв; и имейте это в конце всех ваших петель. Вы также можете разделить внутренние циклы на методы и вернуть вместо break. Вам также следует задаться вопросом о преимуществах раннего прерывания, сможете ли вы повысить производительность за счет распараллеливания или другого алгоритма. В некоторых случаях я даже понимал, что во вложении нет необходимости, циклы можно просто реорганизовать, чтобы они запускались один за другим.
Я никогда не использую метки в своем коде. Я предпочитаю создать охрану и инициализировать его значением ноль или другим необычным значением. Этот охранник часто является объектом результата. Я не видел, чтобы мои коллеги использовали ярлыки, и не нашел их в нашем репозитории. Это действительно зависит от вашего стиля программирования. На мой взгляд, использование меток снизит удобочитаемость, поскольку это не обычная конструкция и обычно не используется в Java.
Многие алгоритмы легче выразить, если вы можете перепрыгнуть через два цикла (или цикл, содержащий оператор switch). Не расстраивайся из-за этого. С другой стороны, это может указывать на слишком сложное решение. Так что отойдите и посмотрите на проблему.
Некоторые люди предпочитают подход «один вход - один выход» ко всем петлям. То есть полное исключение break (и continue) и раннего возврата для циклов. Это может привести к дублированию кода.
Чего я бы категорически не делал, так это введения вспомогательных переменных. Скрытие потока управления внутри состояния добавляет путаницы.
Разделение помеченных петель на два метода может оказаться затруднительным. Исключения, наверное, слишком тяжеловесны. Попробуйте подход с одним входом и одним выходом.
Проголосовал бы за это, если бы не заключительное замечание «попробуйте один вход, подход с одним выходом».
Думаю, время от времени стоит примерять размер. У тебя всегда есть ^ Z.
«Скрытие потока управления внутри состояния добавляет путаницы» - в целом хороший совет
Ярлыки похожи на goto: используйте их экономно и только тогда, когда они сделают ваш код быстрее и, что более важно, более понятно,
e.g., If you are in big loops six levels deep and you encounter a condition that makes the rest of the loop pointless to complete, there's no sense in having 6 extra trap doors in your condition statements to exit out the loop early.
Ярлыки (и goto) не являются злом, просто иногда люди используют их не по назначению. Большую часть времени мы фактически пытаемся написать наш код, чтобы он был понятен вам и следующему программисту. Сделать его сверхбыстрым - второстепенная задача (остерегайтесь преждевременной оптимизации).
Когда ярлыки (и goto) используются неправильно, они делают код менее читаемым, что причиняет горе вам и следующему разработчику. Компилятору все равно.
Да, +1: GOTO не убивают приложения - программисты убивают приложения.
Исторически сложилось так, что программисты использовали GOTO для уничтожения приложений. GOTO получил плохую репутацию не просто так.
Все сводится к письму Дейкстры «Случай против утверждения Goto» / «Go To Statementred Assassred Incredible», который выступает против него из-за тенденции превращения программы в спагетти-код по сравнению с тем, что вы найдете в чем-то более структурированном. На самом деле вы все время используете goto (будь то пауза, продолжение, попытка / ловушка и т. д.). Практически всегда это отбрасывает исполнение вперед. Если вы не дисциплинированы в том, чтобы идти только вперед, вы можете увеличить сложность функции на порядок.
Обратный переход может быть достаточно легким для вас сегодня, но следующий разработчик или вы через 3 года захотите убить SOB, который сэкономил 5 минут работы и оставил им 3 часа, анализируя поток функции.
Я никогда не видел ярлыков, используемых «в дикой природе» в Java-коде. Если вы действительно хотите разорвать вложенные циклы, посмотрите, можете ли вы реорганизовать свой метод, чтобы ранний оператор return делал то, что вы хотите.
Технически, я думаю, нет большой разницы между ранним возвратом и лейблом. На практике, однако, почти каждый разработчик Java видел скорейшее возвращение и знает, что делает. Я предполагаю, что многие разработчики, по крайней мере, будут удивлены этим ярлыком и, вероятно, будут сбиты с толку.
В школе меня учили ортодоксальности единственного входа / единственного выхода, но с тех пор я начал ценить ранние операторы возврата и выход из циклов как способ упростить код и сделать его более понятным.
Я думаю, что с новым циклом for-each метка может быть действительно понятной.
Например:
sentence: for(Sentence sentence: paragraph) {
for(String word: sentence) {
// do something
if (isDone()) {
continue sentence;
}
}
}
Я думаю, что это выглядит действительно ясно, если ваш ярлык такой же, как ваша переменная в новом for-each. На самом деле, может быть, Java должна быть злой и добавлять неявные метки для каждой переменной хе
Что ж, continue sentence; продолжает обрабатывать нет предложение, слова которого (какие?) Были обработаны внутренним циклом: он продолжает _следующее предложение_ / тот же абзац.
Я бы поспорил в их пользу в некоторых местах, я нашел их особенно полезными в этом примере:
nextItem: for(CartItem item : user.getCart()) {
nextCondition : for(PurchaseCondition cond : item.getConditions()) {
if (!cond.check())
continue nextItem;
else
continue nextCondition;
}
purchasedItems.add(item);
}
Что ж, continue nextCondition - это лишний шум.
В редких случаях вам нужны ярлыки, и они могут сбивать с толку, потому что используются редко. Однако, если вам нужно использовать один, используйте его.
Кстати: это компилируется и запускается.
class MyFirstJavaProg {
public static void main(String args[]) {
http://www.javacoffeebreak.com/java101/java101.html
System.out.println("Hello World!");
}
}
Да, и хороший выделитель синтаксиса должен прояснить, почему.
Это ужасный вопрос для собеседования, если только он не для компании, чья кодовая база является полностью запутанной кладжем. Вы никогда не увидите этого в природе, и если вы это сделаете, быстрый поиск в Интернете покажет вам, что это значит. Есть более важные вещи, на которых вы можете тестировать будущих разработчиков, чем глупые загадки.
Подсветка и форматирование кода @studro покажут вам, о чем идет речь;) Дело в том, что вы всегда найдете в коде других людей то, что не так, как вы бы делали или чего ожидали, и как вы с этим справляетесь. Важно то, как вы отвечаете на вопрос, а не ответ, который вы даете. Собеседование должно быть посвящено викторине о том, что вы знаете, но с чем бы вы хотели работать и как вы справляетесь с различными способами ведения дел.
Это определенно неясно; Замечательно сказать: «Это то, как вы с этим справляетесь», но это уловка для бедного разработчика, который, к счастью, знает об этом, и фактор исключения для хорошего разработчика, который не сталкивался с этим в дикой природе (потому что это не не бывает так часто вообще). «Я бы погуглил« ярлыки на Java »», наверное, не подходит для интервью.
Я использовал помеченный Java цикл для реализации метода Sieve для поиска простых чисел (сделано для одной из математических задач проекта Эйлера), что сделало его в 10 раз быстрее по сравнению с вложенными циклами. Например, если (определенное условие) вернуться во внешний цикл.
private static void testByFactoring() {
primes: for (int ctr = 0; ctr < m_toFactor.length; ctr++) {
int toTest = m_toFactor[ctr];
for (int ctr2 = 0; ctr2 < m_divisors.length; ctr2++) {
// max (int) Math.sqrt(m_numberToTest) + 1 iterations
if (toTest != m_divisors[ctr2]
&& toTest % m_divisors[ctr2] == 0) {
continue primes;
}
} // end of the divisor loop
} // end of primes loop
} // method
Я спросил программиста на C++, насколько плохи маркированные циклы, он сказал, что будет использовать их экономно, но иногда они могут пригодиться. Например, если у вас есть 3 вложенных цикла и при определенных условиях вы хотите вернуться к самому внешнему циклу.
Так что у них есть свое применение, это зависит от проблемы, которую вы пытались решить.
Да, вам следует избегать использования меток, если нет особой причины их использовать (уместен пример, упрощающий реализацию алгоритма). В таком случае я бы посоветовал добавить достаточное количество комментариев или другой документации, чтобы объяснить причину этого, чтобы кто-то не пришел позже и не исказил это каким-то понятием «улучшение кода» или «избавление от запаха кода» или какое-то другое потенциально BS оправдание.
Я бы приравнял этот вид вопросов к решению, когда следует или не следует использовать троичное if. Главное объяснение состоит в том, что это может препятствовать удобочитаемости, и если программист не будет очень осторожен, чтобы назвать вещи разумным способом, использование соглашений, таких как метки, может значительно ухудшить ситуацию. Предположим, что в примере, использующем 'nextCondition' и 'nextItem', в качестве имен меток использовались 'loop1' и 'loop2'.
Лично ярлыки - одна из тех функций, которые не имеют для меня особого смысла, за исключением Assembly, BASIC и других подобных ограниченных языков. В Java есть множество более традиционных / регулярных циклов и управляющих конструкций.
Я обнаружил, что метки иногда могут быть полезны в тестах, чтобы разделить обычную настройку, упражнения и фазы проверки и сгруппировать связанные утверждения. Например, используя терминологию BDD:
@Test
public void should_Clear_Cached_Element() throws Exception {
given: {
elementStream = defaultStream();
elementStream.readElement();
Assume.assumeNotNull(elementStream.lastRead());
}
when:
elementStream.clearLast();
then:
assertThat(elementStream.lastRead()).isEmpty();
}
Ваш выбор форматирования может различаться, но основная идея заключается в том, что в данном случае метки лучше, чем комментарии, обеспечивают заметное различие между логическими разделами, составляющими ваш тест. Я думаю, что библиотека Спок просто основывается на этой самой функции, чтобы объявить свои этапы тестирования.
Мне нравится, насколько ты непредубежден :) «Я готов передумать об их использовании»