Pull to refresh

Comments 38

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

использование меток тянется еще со времен Си, причем не только в continue, но и break, можно «прыгать» как вперед, так и назад, ограничение одно: метка не должна выходить за пределы цикла.
удобная штука, когда надо прервать из вложенного цикла во внешний.

з.ы. но стоит отметить, что эта фича используется столь редко, что давно считается дурным тоном — т.е. если вам она понадобилась, то стоит присмотреться к коду, нельзя ли его написать иначе и лучше? (а в некоторых статических анализаторах, например, встроенном в Jetbrains Idea, есть даже предупреждения об использовании break,continue, меток и вложенных циклов)

Про брейк не знал, спасибо!

ограничение одно: метка не должна выходить за пределы цикла
Непонятное ограничение, кстати. Программа на языке высокого уровня (т.е. reducible CFG) состоит из вложенных друг в друга statement'ов, каждый из которых имеет один вход и максимум один выход. 'break' позволяет переместится к выходу любого statement'а в иерархии. Было бы логично, если бы 'continue' позволяло то же самое для входа, но почему-то оно ограничено только входами в циклы.
break\continue с метками и так сильно критиковали, мол, это то же самое, что измененный goto label; очевидно, ограничение потому и наложено, чтобы не использовали управляющую конструкцию для того, для чего она не предназначена.

для сравнения:
в бейсиках 80х годов каждый оператор обязан был иметь числовую метку (не совсем так, можно было группировать операторы) и называлась метка номером строки, а условные операторы не могли быть сложными (не было понятия {блок}), и потому постоянно приходилось использовать goto: в какой-то момент ненависть к такому принуждению визуально прыгать по частям кода зашкалила и оператор выдрали с корнем из всех языков
> Это ты сам придумал или где-то прочитал?
вспомнил, что когда-то давно придумал читал

>Критика goto
вот именно

> Похоже, что отлаживать спагетти-код никогда не приходилось.
Хех, какой только говнокод не приходилось отлаживать… И не только отлаживать (отладчиками), но и, простигосподи, пользоваться print\write\alert
Я про break label узнал в 2016м, когда считал простые числа :).
А ещё можно делать так:
someLabel: {

    if(conditionA) {
        //...
        break someLabel;
    }

    if(conditionB) {
        //...
        break someLabel;
    }

    if(conditionC) {
        //...
        break someLabel;
    }
}

Если выполниться одно из условий, то оператор break someLabel выведет выполнение из блока
> assert может принимать 2 аргумента
при том, что assert может не работать совсем — все зависит от флагов запуска.

> strictfp
лучше не использовать float, а использовать double, а еще лучше — использовать StrictMath

> При вызове vararg-метода без аргументов всё равно создаётся пустой массив
что очень удобно в циклах, ну и логично, если помнить, что vararg — это всего лишь syntax sugar

> Выражение switch-case не поддерживает java.lang.Class
А для чего это может понадобиться? Нет ли специфичного запашка?
image

>
Нет, остальное вообще, извините, детсад, комментарий аж застрял.
Ну про switch это как бы странно относить к разряду вещей, которые мы не знали про Java: это скорее «а с чего бы вдруг оно так было?». Вот четко написано в доке (я смотрел в java 12): The type of the Expression must be char, byte, short, int, Character, Byte, Short, Integer, String, or an enum type (§8.9), or a compile-time error occurs. Вот если бы наоборот, в этом списке был еще Class — можно было бы написать: «а знаете ли вы что вот так можно?».
Так обычно и бывает: когда начинаешь изучать технологию не по верхам (лишь бы скорее начать строчить код), а основательно, вдумчиво, сверяясь с документацией, то всплывает много «интересных вещей, о которых вы могли не знать».
И которые с вероятностью 99.999% никогда не пригодятся и забудутся.
Извините, но наоборот — не зная которые, потратишь в 10 раз больше времени на ловлю багов.
Впрочем, зачастую помогает интуиция\здравый смысл.

А теперь скажите, кому это пригодилось в продакшене?

Мне. На проблему со Спринг Датой я почти наступил.

Двойственное ощущение от статьи. С одной стороны — просвещение, польза! Про «strictfp» не помню, чтобы слышал. С другой стороны — простите, детский сад какой-то.

Если использовать assert, хорошо бы знать, как он работает. Как только он появился, сразу прочитал про него всё, а не остановился на выжимке, что появилась мол, новая функциональность в языке.

Switch-case тоже, базовая конструкция языка, вроде. Либо используем и знаем, как она работает, либо не удивляемся, что она имеет ограничения. Раньше вообще можно было только числа использовать. (Да, тут я рассматриваю char как число). И, на всякий случай, в case можно писать только константу/константное выражение.

Break и continue — я бы удивился, если бы не было возможности указать метку. Как уже говорили выше — если пишешь на java, хорошо бы понимать, откуда растут ноги.

Вызов vararg-метода без аргументов. У меня единственный вопрос, а почему вообще ожидается, что массив, который содержит аргументы, внезапно может оказаться и не массивом вовсе, а null? Тут же, вроде, всё логично: длина массива равна количеству аргументов. Ноль аргументов — массив длины ноль. Или у меня логика ущербная? И предвосхищая комментарий: «ну, производительность-же!», опять же, сошлюсь на логику.

int.class.isAssignableFrom(Integer.class) — ну autoboxing-же. Если об этом не задумываться или не знать о его существовании, то как же жить-то дальше? int.class != Integer.class туда же. Это же базовые понятия языка — примитивные и непримитивные типы.

А по вопросу, помогли ли эти знания в production, скажу, что мат-часть хорошо бы знать. Иначе использовать её на полную не получится. А если не знать, то процесс уже напоминает раскладывание грабель. И очень повезёт, если как в случае с switch — case, код просто не скомпилируется. Так что то, что подобные вещи не знают программисты, которые работают над тем же проектом, это очень даже мешает в production. Поскольку обидно наступать на грабли, подложенные коллегой, который просто не знает базовых вещей.
Switch-case тоже, базовая конструкция языка, вроде. Либо используем и знаем, как она работает, либо не удивляемся, что она имеет ограничения. Раньше вообще можно было только числа использовать. (Да, тут я рассматриваю char как число). И, на всякий случай, в case можно писать только константу/константное выражение.

Вам осталось сделать крошечный шаг до осознания того, что String.class как раз и является постоянной. Я ведь недаром вписал пример про switch-case, эта конструкция не так проста, как кажется, но, похоже, почти никто не заметил скрытого смысла. Думаю, я сделаю про это отдельную запись.

Я не очень хорошо помню, есть ли в спецификации jls/jvms понятие «постоянная». Но вынужден заметить, что ни константным выражением, ни константой String.class не является. Иными словами, на этапе компиляции значение данного выражения не может быть определено. Именно поэтому оно и не может быть использовано в case. Таблицы поиска для switch/case генерируются на этапе компиляции. Для String-значений switch компилируется в код, использующий две таблицы поиска. Первая из них содержит hashCode образцов. То, что вы предлагаете, вынуждает либо отказаться от эффективной реализации switch/case путём замены её на линейную цепочку проверок, либо утяжелить загрузку классов, переложив на неё коррекцию соответствующих таблиц поиска (для эффективного сравнения используется hashCode). Вот такой вот «крошечный шаг».
Иными словами, на этапе компиляции значение данного выражения не может быть определено. Именно поэтому оно и не может быть использовано в case.

Class literal в case нельзя использовать потому, что в JLS11 §14.11 его поддержка не заявлена:


The type of the Expression must be char, byte, short, int, Character, Byte, Short, Integer, String, or an enum type (§8.9), or a compile-time error occurs

java.lang.Class в списке разрешённых типов отсутствует, точка.
Добавят в спецификацию разрешение использовать java.lang.Class — допилят и компилятор и VM.


В какой конкретно байткод это будет транслироваться — дело десятое.


P.S. Class literals, хоть тот же String.class, на уровне байткода вполне себе загружаются из пула констант.

Мы с вами говорим об одном и том же, только по разному. Вы отмечаете, что это не сделано потому, что было заявлено, что это сделано не будет. Я отмечаю, что реализовавать это было бы весьма проблематичто, поэтому, скорее всего, и было принято решение этого не делать. Им и со строками-то уже сильно выворачиваться пришлось. Ведь в конечном итоге, это не вызывает проблем с совместимостью, и, я думаю, много кто просил расширить конструкцию switch-case существенно больше, чем это было сделано.

Добавят в спецификацию разрешение использовать java.lang.Class — допилят и компилятор и VM.

В какой конкретно байткод это будет транслироваться — дело десятое.

По-моему, это утверждение слегка неосторожное. Складывается такое впечатление, что главное — это принять решение, а выполнимо ли оно с заданным качеством — «дело десятое»…
Мы с вами говорим об одном и том же, только по разному.

Нет, ваша позиция — «Это очень сложно, потому и не сделали», моя — «Руки не дошли, вот и не сделали».


В пользу моей точки зрения говорит JDK-8213076 Pattern matching for switch, который как раз и посвящён добавлению этой возможности в язык, а вовсе не объяснению того, что это слишком сложно сделать.


Им и со строками-то уже сильно выворачиваться пришлось.

Сомневаюсь, что реализация вызвала сколь-нибудь серьёзные трудности. Принять решение — да, пришлось.


Складывается такое впечатление, что главное — это принять решение, а выполнимо ли оно с заданным качеством — «дело десятое»…

Не нужно передёргивать, я говорил про байткод. На уровне байткода этот switch вполне может выродиться в пару invokedynamic/tableswitch, которые JIT заменит на intrinsics.
Синтаксический сахар это совсем не космические технологии.

В пользу моей точки зрения говорит JDK-8213076 Pattern matching for switch...
Уели. Согласен.
Не нужно передёргивать, я говорил про байткод
Я написал то, как можно легко понять ваше высказывание. Поэтому, собственно, и абзац начал с: «По-моему, это утверждение слегка неосторожное».
Вам осталось сделать крошечный шаг до осознания того, что String.class как раз и является постоянной.

С чего бы? Я могу один и тот же класс грузить разными class loader'ми и это будут разные объекты.

Я ведь не зря написал String.class и Integer.class: классы из java.lang, ЕМНИП, загружаются при запуске виртуальной машины и только один раз.

Про continue/break и varargs знал, а вот про assert — нет. Если честно, вообще не помню, когда я последний раз видел assert в коде

А вот такую вещь вы знали? В Java есть ещё одна форма комментариев:
this_is_for_loop:
for (int i = 0; i < 10; i++) {
    print_variable_i:
    System.out.println(i);
}

Не знал )) Ставлю жирный плюс!

А есть ещё одна форма комментариев, уже "комбинированная" :)


trollface.jpg
public class C {
    public static void main(String[] args) {
        http://habr.com
    }
}
Не скомпилируется. Нужен statement.

Это был пример с подсветкой синтаксиса, а не рабочий вариант. :)

Это ж метка цикла.

Не знал, что System.out.println это цикл

Кстати, IntelliJ IDEA умеет переписать за вас свитч по классам. Так что смело свитчуйтесь по любым объектам, IDEA всё поправит:



Результат:


if (String.class.equals(clazz)) {
    return "str";
} else if (Integer.class.equals(clazz)) {
    return "int";
}
return "obj";

Я про неё узнал только что из твоего верхнего комментария )

Sign up to leave a comment.

Articles