Я столкнулся с ситуацией, когда в непустом методе отсутствует оператор return, а код все еще компилируется. Я знаю, что операторы после цикла while недоступны (мертвый код) и никогда не будут выполнены. Но почему компилятор даже не предупреждает о возврате чего-либо? Или почему язык позволяет нам иметь не пустой метод, имеющий бесконечный цикл и ничего не возвращающий?
public int doNotReturnAnything() {
while(true) {
//do something
}
//no return statement
}
Если я добавляю оператор break (даже условный) в цикл while, компилятор жалуется на печально известные ошибки: Method does not return a value
в Eclipse и Not all code paths return a value
в Visual Studio.
public int doNotReturnAnything() {
while(true) {
if(mustReturn) break;
//do something
}
//no return statement
}
Это верно как для Java, так и для C #.
unreachable statement
наличие чего-либо после цикла.Ответы:
Правило для не пустых методов состоит в том, что каждый возвращаемый путь к коду должен возвращать значение , и это правило выполняется в вашей программе: возвращаемые значения с нуля из нулевых путей кода возвращают значение. Правило не «у каждого не пустого метода должен быть путь к коду, который возвращает».
Это позволяет вам писать методы-заглушки, такие как:
Это не пустой метод. Это должен быть не пустой метод, чтобы удовлетворить интерфейс. Но кажется глупым делать эту реализацию незаконной, потому что она ничего не возвращает.
То, что ваш метод имеет недоступную конечную точку, потому что
goto
(помните, awhile(true)
- это просто более приятный способ написанияgoto
) вместо athrow
(что является другой формойgoto
) не имеет значения.Потому что у компилятора нет веских доказательств того, что код неправильный. Кто-то написал,
while(true)
и похоже, что тот, кто это сделал, знал, что делает.Смотрите мои статьи на эту тему здесь:
ATBG: де-факто и де-юре достижимость
И вы могли бы также рассмотреть чтение спецификации C #.
источник
public int doNotReturnAnything() {
boolean flag = true;
while (flag) {
//Do something
}
//no return
}
этот код также не имеет точки останова. Итак, теперь, как компилятор знает, что код неверен.if
,while
,for
,switch
и т.д., ветвистые конструкции , которые действуют на константах рассматриваются как безусловные ветви компилятора. Точное определение константного выражения в спецификации. Ответы на ваши вопросы в спецификации; Мой совет, что вы читаете это.Every code path that returns must return a value
Лучший ответ. Четко отвечает на оба вопроса. СпасибоКомпилятор Java достаточно умен, чтобы найти недоступный код (код после
while
цикла)и поскольку он недоступен , нет смысла добавлять туда
return
оператор (послеwhile
окончания)то же самое касается условного
if
поскольку булево условие
someBoolean
может вычисляться только для одногоtrue
илиfalse
, нет необходимостиreturn
явно указывать послеif-else
, потому что этот код недоступен , и Java не жалуется на это.источник
return
оператор в недоступном коде, но не имеет отношения к тому, почему вам не нужен какой-либоreturn
оператор в коде OP.public int doNotReturnAnything() {
if(true){
System.exit(1);
}
return 11;
}
public int doNotReturnAnything() {
while(true){
System.exit(1);
}
return 11;// Compiler error: unreachable code
}
System.exit(1)
убьет программу. Он может обнаруживать только определенные типы недоступного кода.System.exit(1)
что убьет программу, мы можем использовать любуюreturn statement
, теперь компилятор распознаетreturn statements
. И поведение такое же, возврат требуется для,if condition
но не дляwhile
.while(true)
Компилятор знает, что
while
цикл никогда не перестанет выполняться, поэтому метод никогда не завершится, следовательно,return
оператор не нужен.источник
Учитывая, что ваш цикл выполняется с константой - компилятор знает, что это бесконечный цикл - это означает, что метод, в любом случае, никогда не вернется.
Если вы используете переменную - компилятор будет применять правило:
Это не скомпилируется:
источник
Спецификация Java определяет концепцию, называемую
Unreachable statements
. Вам не разрешено иметь недоступный оператор в вашем коде (это ошибка времени компиляции). Вам даже не разрешено иметь оператор return через некоторое время (true); заявление в Java.while(true);
Заявление делает следующие утверждения недостижимы по определению, поэтому вам не нужноreturn
заявление.Обратите внимание, что хотя проблема остановки в общем случае неразрешима, определение Unreachable Statement является более строгим, чем просто остановка. Это решает очень конкретные случаи, когда программа определенно не останавливается. Компилятор теоретически не способен обнаружить все бесконечные циклы и недостижимые операторы, но он должен обнаруживать конкретные случаи, определенные в спецификации (например,
while(true)
случай)источник
Компилятор достаточно умен, чтобы узнать, что ваш
while
цикл бесконечен.Таким образом, компилятор не может думать за вас. Не могу понять, почему вы написали этот код. То же самое относится к возвращаемым значениям методов. Java не будет жаловаться, если вы ничего не сделаете с возвращаемыми значениями метода.
Итак, чтобы ответить на ваш вопрос:
Компилятор анализирует ваш код и, обнаружив, что ни один путь выполнения не приводит к падению конца функции, он завершается с помощью OK.
Могут быть законные причины для бесконечного цикла. Например, многие приложения используют бесконечный основной цикл. Другим примером является веб-сервер, который может бесконечно ждать запросов.
источник
В теории типов есть нечто, называемое нижним типом, которое является подклассом любого другого типа (!) И используется для указания на отсутствие завершения среди других вещей. (Исключения могут считаться типом не-завершения - вы не завершаете по обычному пути.)
Таким образом, с теоретической точки зрения, эти операторы, которые не являются завершающими, могут рассматриваться как возвращающие что-то типа Bottom, который является подтипом типа int, так что вы (вроде бы) получаете возвращаемое значение в конце концов с точки зрения типа. И совершенно нормально, что нет никакого смысла в том, что один тип может быть подклассом всего остального, включая int, потому что вы никогда не возвращаете его.
В любом случае, с помощью явной теории типов или нет, компиляторы (составители компиляторов) признают, что запрашивать возвращаемое значение после не завершающего оператора глупо: нет никакого возможного случая, когда вам может понадобиться это значение. (Было бы неплохо, чтобы ваш компилятор предупреждал вас, когда он знает, что что-то не прекратится, но похоже, что вы хотите, чтобы он что-то возвращал. Но лучше оставить это для проверки стиля, но, возможно, вам нужна сигнатура типа, которая путь по какой-то другой причине (например, подклассы), но вы действительно хотите не прекращение.)
источник
Не существует ситуации, в которой функция может достичь своего конца, не возвращая соответствующее значение. Поэтому компилятору не на что жаловаться.
источник
Visual Studio имеет интеллектуальный механизм для определения, если вы ввели тип возврата, тогда он должен иметь оператор return в функции / методе.
Как и в PHP Ваш тип возврата true, если вы ничего не возвращали. Компилятор получает 1, если ничего не вернулось.
По состоянию на это
Компилятор знает, что, хотя само утверждение имеет бесконечную природу, поэтому не стоит его рассматривать. и php-компилятор автоматически получит true, если вы напишите условие в выражении while.
Но не в случае VS он вернет вам ошибку в стеке.
источник
Ваш цикл while будет работать вечно и, следовательно, не выйдет вовне; он будет продолжать выполняться. Следовательно, внешняя часть while {} недоступна, и нет смысла в возврате или нет. Компилятор достаточно умен, чтобы выяснить, какая часть достижима, а какая нет.
Пример:
Приведенный выше код не будет компилироваться, потому что может быть случай, когда значение переменной x изменяется внутри тела цикла while. Так что это делает внешнюю часть цикла while достижимой! И, следовательно, компилятор выдаст ошибку «оператор возврата не найден».
Компилятор не достаточно умен (или, скорее, ленив;)), чтобы выяснить, будет ли изменено значение x или нет. Надеюсь, это все прояснит.
источник
int x = 1; while(x * 0 == 0) { ... }
это бесконечный цикл, но в спецификации сказано, что компилятор должен делать вычеты потока управления только тогда, когда выражение цикла является постоянным , а спецификация определяет постоянное выражение как не содержащее переменных . Поэтому компилятор был слишком умен . В C # 3 я сделал так, чтобы компилятор соответствовал спецификации, и с тех пор он намеренно стал менее умным в отношении таких выражений.«Почему компилятор даже не предупреждает о возврате чего-либо? Или почему язык позволил бы нам иметь не пустотный метод с бесконечным циклом и ничего не возвращать?».
Этот код действителен и на всех других языках (возможно, кроме Haskell!). Потому что первое предположение заключается в том, что мы «намеренно» пишем некоторый код.
И бывают ситуации, когда этот код может быть полностью действительным, например, если вы собираетесь использовать его в качестве потока; или если он возвращал a
Task<int>
, вы могли бы сделать некоторую проверку ошибок на основе возвращенного значения int - которое не должно возвращаться.источник
Я могу ошибаться, но некоторые отладчики допускают изменение переменных. Здесь, хотя x не модифицируется кодом и оптимизируется с помощью JIT, можно изменить x на false, и метод должен что-то возвращать (если это разрешено отладчиком C #).
источник
Специфика случая Java для этого (которая, вероятно, очень похожа на случай C #) связана с тем, как компилятор Java определяет, может ли метод вернуться.
В частности, правила таковы, что метод с возвращаемым типом не должен иметь возможность нормально завершаться и вместо этого должен всегда завершаться преждевременно (здесь резко с помощью оператора возврата или исключения) согласно JLS 8.4.7 .
Компилятор проверяет , возможно ли нормальное завершение, основываясь на правилах, определенных в JLS 14.21 Недоступные утверждения, так как он также определяет правила для нормального завершения.
Примечательно, что правила для недостижимых операторов делают особый случай только для циклов, которые имеют определенное
true
константное выражение:Таким образом, если
while
оператор может завершиться нормально , тогда оператор возврата ниже необходим, поскольку код считается достижимым, и любойwhile
цикл без оператора достижимости или константы сtrue
выражением считается способным завершиться нормально.Эти правила означают , что ваше
while
заявление с постоянным истинным выражением и безbreak
никогда не считало , чтобы завершить нормально , и поэтому любой код под ним не разу не считаются достижимыми . Конец метода находится ниже цикла, и поскольку все, что находится ниже цикла, недоступно, так же как и конец метода, и, таким образом, метод не может завершиться нормально (именно это ищет компилятор).if
операторы, с другой стороны, не имеют специального исключения в отношении константных выражений, которые предоставляются циклам.Для сравнения:
С участием:
Причина различия довольно интересна и связана с желанием разрешить флаги условной компиляции, которые не вызывают ошибок компиляции (из JLS):
Почему оператор условного прерывания приводит к ошибке компилятора?
Как указано в правилах достижимости цикла, цикл while может также завершиться нормально, если он содержит достижимый оператор break. Поскольку правила достижимости предложения then
if
оператора вообще не принимают во внимание условие условия , предложение then такого условного оператора всегда считается достижимым.if
if
Если значение
break
достижимо, то код после цикла снова считается также достижимым. Поскольку нет доступного кода, который приводит к внезапному завершению после цикла, считается, что метод может нормально завершиться, и поэтому компилятор помечает его как ошибку.источник