2010-09-25 1 views
76

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

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

Test.java:7: unreachable statement

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

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

+10

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

ответ

58

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

Здесь есть аналогичный вопрос: Unreachable code: error or warning?, в котором автор говорит: «Лично я сильно чувствую, что это должна быть ошибка: если программист пишет фрагмент кода, он всегда должен быть с намерением фактически запустить его в какой-то сценарий ». Очевидно, что разработчики языка Java согласны.

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


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

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

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


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

+2

+1 для того, чтобы просто получить его правильно – willcodejavaforfood

+22

_Очевидно, разработчики языка Java согласны. «Языковые дизайнеры Java» - это люди и склонны к ошибкам. Лично я считаю, что другая сторона в обсуждаемой вами дискуссии имеет гораздо более веские аргументы. –

+2

Я не думаю, что это объясняет, почему «бессмысленный» код достаточен для оправдания ошибки компилятора, которая обычно резервируется для проблем синтаксиса. – Mike

18

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

+1

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

+1

Для отладки раннего возвращения требуется еще пять секунд, чтобы прокомментировать строки, следующие за вашим ранним возвратом. Небольшая цена, которую можно сыграть за ошибки, предотвращенные путем недопущения ошибки. – SamStephens

+6

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

5

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

public void myMethod(){ 

    someCodeHere(); 

    if(1 < 2) return; // compiler isn't smart enough to complain about this 

    moreCodeHere(); 

} 

Компилятор не достаточно умен, чтобы жаловаться на это.

+6

Вопрос вот почему? Недостижимый код не имеет смысла для компилятора. Так что единственной аудиторией для него являются разработчики. Используйте комментарий. – SamStephens

+3

Итак, я получаю downvotes, потому что я согласен с тем, как java-парни отказались от их компиляции? Jeez ... –

+0

Просто подождите, пока я не начну обсуждение «где к скобкам идти». –

5

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

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

0

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

41

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

if (true) return; 

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

Java имеет немного поддержку «условной компиляции»

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

if (false) { x=3; } 

does not result in a compile-time error. An optimizing compiler may realize that the statement x=3; will never be executed and may choose to omit the code for that statement from the generated class file, but the statement x=3; is not regarded as "unreachable" in the technical sense specified here.

The rationale for this differing treatment is to allow programmers to define "flag variables" such as:

static final boolean DEBUG = false; 

and then write code such as:

if (DEBUG) { x=3; } 

The idea is that it should be possible to change the value of DEBUG from false to true or from true to false and then compile the code correctly with no other changes to the program text.

+2

По-прежнему не понимайте, почему вы потрудились с трюком, который вы показываете. Недостижимый код не имеет смысла для компилятора. Так что единственной аудиторией для него являются разработчики. Используйте комментарий. Хотя я предполагаю, что если вы добавляете возврат временно, использование обходного пути может быть менее быстрым, чем просто возвращение в исходное положение, и комментирование следующего кода. – SamStephens

+7

@SamStephens Но каждый раз, когда вы хотели переключиться, вам нужно было запомнить все места, где вы должны прокомментировать код и где вам нужно сделать обратное. Вам нужно будет прочитать весь файл, изменив исходный код, возможно, время от времени делая некоторые тонкие ошибки, вместо того, чтобы просто заменить «true» на «false» в одном месте. Я думаю, что лучше закодировать логику переключения один раз и не трогать его, если это необходимо. – Robert

+0

«Любой, кто читает код, догадается, что это должно быть сделано сознательно». По сути, это проблема, люди не должны гадать, они должны понимать. Вспоминание кода - это общение с людьми, а не просто инструкции для компьютеров.Если это что-то другое, кроме чрезвычайно временного, вы должны использовать конфигурацию, на мой взгляд. Глядя на то, что вы показываете выше, 'if (true) return;' не указывает, ПОЧЕМУ вы пропускаете логику, тогда как 'if (BEHAVIOURDISABLED) возвращается,' сообщает намерение. – SamStephens

0

Если причина для разрешения if (aBooleanVariable) return; someMoreCode; это позволить флаги, то тот факт, что if (true) return; someMoreCode; не генерирует компиляции ошибки времени кажется несогласованностью в политике генерации исключения CodeNotReachable, поскольку компилятор «знает», что true не является флагом (а не переменной).

Две другие способы, которые могут быть интересными, но не относятся к отключив часть кода-методов, а также if (true) return:

Теперь, вместо того чтобы сказать if (true) return; вы можете сказать assert false и добавить -ea OR -ea package OR -ea className к аргументы jvm. Хорошим моментом является то, что это допускает некоторую детализацию и требует добавления дополнительного параметра к вызову jvm, поэтому нет необходимости устанавливать флаг DEBUG в коде, но добавленный аргумент во время выполнения, что полезно, когда цель не является разработчик и перекомпиляция & Передача байт-кода требует времени.

Существует также способ System.exit(0), но это может быть перебор, если вы поместите его на Java в JSP, то он прекратит работу сервера.

Помимо того, что Java по-умолчанию является языком «няня», я бы скорее использовал что-то родное, например C/C++, для большего контроля.

+0

Изменение чего-либо из переменной 'static final', которая устанавливается в статическом блоке инициализации переменной' static final', которая является установленный в его декларации, не должен быть изменением. Весьма правдоподобно, что, когда класс сначала написан, он иногда не мог что-то сделать (и не знал до времени выполнения, сможет ли он это сделать или нет), но более поздние версии этого класса могли бы делайте это действие всегда. Изменение 'myClass.canFoo' константы должно сделать' if (myClass.canFoo) myClass.Foo(); else doSomethingElse(); 'более эффективный - не сломать его. – supercat

14

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

В случае Java это на самом деле не вариант. Ошибка «недостижимого кода» исходит не из того, что разработчики JVM думали защищать разработчиков от чего-либо или быть более бдительными, но из требований спецификации JVM.

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

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

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

в строке 3, JVM проверит, что обе ветви «если» только хранится в (это просто локальная переменная # 0) то, что совместимо с объектом (с вот как код из строки 3 и далее будет обрабатывать локальный var # 0).

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

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

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

+0

Насколько агрессивной является система предупреждения о мертвом коде Java? Может ли это быть выражено как часть грамматики (например, '{[flowingstatement;] *}' => 'flowingstatement',' {[flowingstatement;] * stoppingstatement;} '=>' stoppingstatement', 'return' =>' stoppingstatement ',' if (condition) stoppingstatement; else stoppingstatement' => 'stoppingstatement;' и т. д.? – supercat

+0

Я плохо разбираюсь в грамматике, но я так считаю, да. Однако «остановка» может быть локальной, например оператор «break» внутри цикла. Кроме того, конец метода является неявным оператором остановки для уровня метода, если метод недействителен. «throw» также будет явным оператором остановки. –

+0

Что бы сказал стандарт Java о чем-то вроде 'void blah() {try {return;} catch (RuntimeError ex) {} DoSomethingElse();}' Будет ли Java squawk, что не было никакого способа, чтобы блок 'try' мог фактически выйти через исключение, или это что любое исключенное исключение может возникнуть в любом блоке 'try'? – supercat

 Смежные вопросы

  • Нет связанных вопросов^_^