Вопрос-ответ

Why does Java have an "unreachable statement" compiler error?

Почему в Java ошибка компилятора "unreachable statement"?

Я часто обнаруживаю, что при отладке программы удобно (хотя, возможно, это плохая практика) вставлять оператор return внутри блока кода. Я мог бы попробовать что-то подобное в Java ....

class Test {
public static void main(String args[]) {
System.out.println("hello world");
return;
System.out.println("i think this line might cause a problem");
}
}

конечно, это привело бы к ошибке компилятора.


Тест.java: 7: недоступный оператор


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

Это просто Java пытается быть нянькой, или есть веская причина списать это на ошибку компилятора?

Переведено автоматически
Ответ 1

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

Здесь есть похожий вопрос: Недоступный код: ошибка или предупреждение?, в котором автор говорит: "Лично я твердо убежден, что это должна быть ошибка: если программист пишет фрагмент кода, это всегда должно быть с намерением фактически запустить его в каком-то сценарии". Очевидно, разработчики языка Java согласны.

Должен ли недоступный код препятствовать компиляции - это вопрос, по которому никогда не будет консенсуса. Но именно поэтому разработчики Java сделали это.


Ряд людей в комментариях отмечают, что существует множество классов недоступного кода, которые Java не предотвращает компиляцию. Если я правильно понимаю последствия Gödel , ни один компилятор не может перехватить все классы недоступного кода.

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

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


(Прежде чем вы проголосуете против: вопрос не в том, должна ли в Java быть ошибка компилятора недоступного оператора. Вопрос в том, почему в Java ошибка компилятора недоступного оператора. Не отвергайте меня только потому, что вы считаете, что Java приняла неправильное дизайнерское решение.)

Ответ 2

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

if (true) return;

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

В Java есть небольшая поддержка "условной компиляции"

http://java.sun.com/docs/books/jls/third_edition/html/statements.html#14.21


if (false) { x=3; }

не приводит к ошибке во время компиляции
. Оптимизирующий компилятор может
понять, что оператор x = 3;
никогда не будет выполнен, и может выбрать
исключить код для этого оператора из
сгенерированного файла класса, но оператор
x = 3; не рассматривается как
"недостижимый" в техническом смысле
указано здесь.


Обоснование такого отличающегося подхода заключается в том, чтобы позволить программистам определять "переменные флага", такие как:


static final boolean DEBUG = false;

а затем напишите код, такой как:


if (DEBUG) { x=3; }

Идея в том, что должна быть возможность
изменить значение DEBUG с
false на true или с true на false
и затем скомпилировать код правильно
без каких-либо других изменений в программе
текст.


Ответ 3

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

Ответ 4

Я только сейчас заметил этот вопрос и хотел добавить к нему свои 0,02 доллара.

В случае Java это на самом деле не вариант. Ошибка "unreachable code" возникает не из-за того, что разработчики JVM думали защитить разработчиков от чего-либо или проявить дополнительную бдительность, а из-за требований спецификации JVM.

И компилятор Java, и JVM используют так называемые "карты стека" - определенную информацию обо всех элементах в стеке, выделенных для текущего метода. Тип каждого слота стека должен быть известен, чтобы инструкция JVM не заменяла элемент одного типа другим типом. Это в основном важно для предотвращения использования числового значения в качестве указателя. С помощью Java assembly можно попытаться ввести / сохранить число, но затем вывести / загрузить ссылку на объект. Однако JVM отклонит этот код во время проверки класса, то есть когда создаются карты стека и тестируются на согласованность.

Чтобы проверить карты стека, виртуальная машина должна пройти по всем путям кода, существующим в методе, и убедиться, что независимо от того, какой путь кода когда-либо будет выполнен, данные стека для каждой инструкции согласуются с тем, что любой предыдущий код отправил / сохранил в стеке. Итак, в простом случае:

Object a;
if (something) { a = new Object(); } else { a = new String(); }
System.out.println(a);

в строке 3 JVM проверит, что обе ветви 'if' сохранили только в a (который является просто локальной переменной # 0) что-то, что совместимо с Object (поскольку именно так код из строки 3 и далее будет обрабатывать локальную переменную # 0).

Когда компилятор добирается до недоступного кода, он не совсем понимает, в каком состоянии может находиться стек в этот момент, поэтому не может проверить его состояние. На этом этапе он больше не может полностью скомпилировать код, поскольку также не может отслеживать локальные переменные, поэтому вместо того, чтобы оставить эту двусмысленность в файле класса, он выдает фатальную ошибку.

Конечно, простое условие типа if (1<2) обманет его, но на самом деле это не так - оно дает ему потенциальную ветвь, которая может привести к коду, и, по крайней мере, и компилятор, и виртуальная машина могут определить, как элементы стека могут использоваться дальше.

P.S. Я не знаю, что именно .NET делает в этом случае, но я полагаю, что это также приведет к сбою компиляции. Обычно это не является проблемой для любых компиляторов машинного кода (C, C ++, Obj-C и т.д.)

java