Следует ли мне избегать использования инструкций Java Label?


сегодня у меня был коллега, который предложил мне рефакторинг моего кода, чтобы использовать оператор label для управления потоком через 2 вложенных цикла for, которые я создал. Я никогда не использовал их раньше, потому что лично я думаю, что они снижают читаемость программы. Однако я готов изменить свое мнение об их использовании, если аргумент достаточно тверд. Каковы мнения людей о заявлениях лейбла?

11 66

11 ответов:

многие алгоритмы выражаются более легко, если вы можете перейти через два цикла (или цикл, содержащий оператор switch). Не расстраивайся из-за этого. С другой стороны, это может указывать на чрезмерно сложное решение. Так что отойдите и посмотрите на проблему.

некоторые люди предпочитают подход "один вход, один выход" для всех циклов. То есть, избегая разрыва (и продолжения) и раннего возврата для циклов в целом. Это может привести к некоторому дублированию кода.

Что бы я сделал настоятельно избегайте введения вспомогательных переменных. Скрытие потока управления в состоянии добавляет путаницы.

разбиение помеченных петель на два метода вполне может быть сложным. Исключения, вероятно, слишком тяжелы. Попробуйте один вход, один выход подход.

метки похожи на goto: используйте их экономно, и только тогда, когда они делают ваш код быстрее и что еще более важно, более понятно,

например, если вы находитесь в больших петлях глубиной шесть уровней, и вы сталкиваетесь с условием, которое делает остальную часть цикла бессмысленной для завершения, нет смысла иметь 6 дополнительных люков в ваших заявлениях о состоянии, чтобы выйти из цикла рано.

ярлыки (и Гото) не злые, это просто так иногда люди используют их в плохих целях. Большую часть времени мы на самом деле пытаемся написать наш код, чтобы он был понятен вам и следующему программисту, который приходит. Создание uber-fast является вторичной проблемой (будьте осторожны с преждевременной оптимизацией).

когда ярлыки (и goto) используются неправильно, они делают код менее читаемым, что вызывает горе для вас и следующего разработчика. Компилятору все равно.

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

кстати: это компилируется и работает.

class MyFirstJavaProg {  
        public static void main(String args[]) {
           http://www.javacoffeebreak.com/java101/java101.html
           System.out.println("Hello World!");
        }
}

Мне любопытно услышать, какова ваша альтернатива ярлыкам. Я думаю, что это в значительной степени сводится к аргументу "return as early as possible" против "use a variable to hold the return value, and only return at the end."

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

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

технически, я думаю, что нет большой разницы между ранним возвращением и ярлыком. Практически, однако, почти каждый разработчик Java видел раннее возвращение и знает, что он делает. Я бы предположил, что многие разработчики, по крайней мере, будут удивлены ярлыком и, вероятно, будут смущенный.

меня учили единственному входу / единственному выходу православия в школе, но с тех пор я стал ценить ранние заявления о возврате и вырваться из циклов как способ упростить код и сделать его более ясным.

Я бы поспорил в пользу них в некоторых местах, я нашел их особенно полезными в этом примере:


nextItem: for(CartItem item : user.getCart()) {

  nextCondition : for(PurchaseCondition cond : item.getConditions()) {
     if(!cond.check())
        continue nextItem;
     else
        continue nextCondition;

  }
  purchasedItems.add(item);
}

Я думаю, что с новым циклом for-each метка может быть действительно ясной.

например:

sentence: for(Sentence sentence: paragraph) {
  for(String word: sentence) {
    // do something
    if(isDone()) {
      continue sentence;
    }
  }
}

Я думаю, что это выглядит действительно ясно, если ваша метка такая же, как и ваша переменная в новом for-each. На самом деле, возможно, Java должна быть злой и добавлять неявные метки для-каждой переменной heh

я использовал цикл с надписью Java для реализации метода сита для поиска простых чисел (выполненный для одной из математических задач Эйлера проекта), что сделало его в 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 вложенных цикла и на определенных условиях, вы хотите вернуться к внешний цикл.

таким образом, у них есть свои применения, это зависит от проблемы, которую вы пытались решить.

Я никогда не использую метки в моем коде. Я предпочитаю создать guard и инициализировать его в null или другое необычное значение. Этот охранник часто является объектом результата. Я не видел ни одного из моих коллег, использующих ярлыки, и не нашел их в нашем репозитории. Это действительно зависит от вашего стиля кодирования. На мой взгляд, использование меток уменьшит читаемость, поскольку это не обычная конструкция, и обычно она не используется в Java.

Да, вы должны избегать использования label, если нет конкретной причины их использовать (пример этого, упрощающий реализацию алгоритма, уместен). В таком случае я бы посоветовал добавить достаточные комментарии или другую документацию, чтобы объяснить причины этого, чтобы кто-то не пришел позже и не искалечил его из какого-то понятия "улучшения кода" или "избавления от запаха кода" или какого-то другого потенциального оправдания BS.

Я бы приравнял такого рода вопрос с решением, когда следует или не следует использовать троичный if. Главное обоснование заключается в том, что это может затруднить читаемость, и если программист не будет очень осторожен, чтобы назвать вещи разумным образом, то использование соглашений, таких как ярлыки, может сделать вещи намного хуже. Предположим, например, используя 'nextCondition' и 'nextItem' использовали 'loop1 и loop2 для имени метки.

лично этикетки являются одной из тех особенностей, которые не имеют большого смысла для меня, за пределами Ассемблер или базовый и другие столь же ограниченные языки. 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();
}

ваши варианты форматирования могут отличаться, но основная идея заключается в том, что метки в этом случае обеспечивают заметное различие между логическими разделами, содержащими ваш тест, лучше, чем комментарии. Я думаю, что Спок библиотека просто строится на этой самой функции, чтобы объявить ее тест фазы.