Почему я не могу явно вернуть void из метода? - PullRequest
55 голосов
/ 17 октября 2011
void run() {
    ...
    if (done) return cancel();
    ...
}

, где cancel() возврат void. Это не скомпилируется ... и я могу почти понять, почему. Но если я хочу вернуть пустоту из пустоты, почему бы и нет? Вместо этого я пишу что-то вроде этого:

if (done) {
    cancel();
    return;
}

Я не ищу предложений по стилю кода, я хочу знать, почему Java явно запрещает этот тип возврата void. Любая информация ценится, спасибо.

Ответы [ 14 ]

25 голосов
/ 17 октября 2011

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

С JLS

Оператор возврата без выражения должен содержаться в теле метода, который объявлен с использованием ключевого слова void, чтобы не возвращатьлюбое значение (§8.4) или в теле конструктора (§8.8).

далее

Если быть точным, оператор возврата без выражения всегда завершается преждевременно, причиной является возврат без значения

24 голосов
/ 17 октября 2011

Оператор return с выражением возвращает значение этого выражения.Тип cancel() является пустым выражением - он не имеет значение.

Логически вы хотите выполнить cancel(), а затем вернуть - вот что вам нужносказать.Два действия (вызов cancel(), а затем возврат) логически различаются.

Теперь Java может иметь вид «единичный» тип вместо void- но это повлияет не только на возвращаемые значения.

9 голосов
/ 17 октября 2011

Это все равно что писать:

void v=(void)1; 
return (v);

Итак, я думаю, void - это не type в Java.

В C ++ return cancel(); допустимо.

Как программист на C ++, знакомый с Java, ответ таков: многие вещи не поддерживаются в синтаксисе Java.Может быть, для простоты или читабельности.

Примечание: объявление void f() похоже на объявление procedure f() в паскале, и процедура не может вернуть любое значение, такое как функции, поэтому мы должны вызвать их вотдельное утверждение.

6 голосов
/ 17 октября 2011

void не тип. Однако, если вы используете тип Void вместо ключевого слова void, ваш код будет работать, но: вам придется вручную return null во всех точках выхода из вашего метода.

5 голосов
/ 17 октября 2011

Потому что вы не возвращаете void. void не является значением, поэтому его нельзя вернуть.

4 голосов
/ 17 октября 2011

Это тавтология. Значение void определяет, что метод не имеет возвращаемого значения. Следовательно, как вы можете «вернуть пустоту», когда пустота вообще не вернется?

3 голосов
/ 19 октября 2011

Краткий ответ

Оператор return cancel() должен возвращать допустимое значение, но объявление метода void run() объявляет, что run() не возвращает значение;следовательно, return cancel() в run() является ошибкой.Оператор return (без выражения) пытается передать управление вызывающей стороне и используется, когда тип возвращаемого метода равен void;следовательно, не ошибка.

Длинный ответ

Секция JLS The *return* Statement сообщает:

Aоператор return без выражения пытается передать управление вызывающему методу или конструктору, который его содержит.[...] Оператор return с выражением должен содержаться в объявлении метода, которое объявлено для возврата значения (§8.4), иначе произойдет ошибка времени компиляции.Выражение должно обозначать переменную или значение некоторого типа T, иначе произойдет ошибка времени компиляции.Тип T должен быть назначен (§5.2) объявленному типу результата метода, иначе произойдет ошибка времени компиляции.

Раздел JLS Method Return Type сообщает:

Возвращаемый тип метода объявляет тип значения, которое возвращает метод, если он возвращает значение, или утверждает, что метод void.Объявление метода d1 с типом возврата R1 является заменяемым типом возврата для другого метода d2 с типом возврата R2, если и только если выполняются следующие условия: [...] * Если R1 не имеет значения, тогда R2 не имеет значения.

JLS Types, Values, and Variables глава , первый абзац гласит:

Язык программирования Java является строго типизированным языком, что означает, что каждая переменная и каждое выражениеимеет тип, который известен во время компиляции.Типы ограничивают значения, которые может содержать переменная (§4.12) или которые может создавать выражение, ограничивают операции, поддерживаемые этими значениями, и определяют смысл операций.

JLS The Kinds of Types and Values section состояния:

В языке программирования Java существует два типа типов: примитивные типы (§4.2) и ссылочные типы (§4.3).Соответственно, существует два вида значений данных, которые могут храниться в переменных, передаваться в качестве аргументов, возвращаться методами и обрабатываться: примитивные значения (§4.2) и ссылочные значения (§4.3).

Еще несколько цитат.В разделе JLS Expression Statements указано:

В отличие от C и C ++, язык программирования Java допускает использование только определенных форм выражений в качестве операторов выражений.Обратите внимание, что язык программирования Java не допускает, чтобы «cast to void» -void не являлся типом

Раздел JLS Method Body сообщает:

Если метод объявлен как void, то его тело не должно содержать никакого оператора возврата (§14.17), который имеет выражение.

И, наконец, раздел JLS Method Declarations состояния:

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

Теперь, когда мы собираем все это вместе, мы можем вывести следующее:

  • Если в выражении return содержится выражение, выражение должно получить допустимое значение.
  • Допустимое return значение выражения должно быть примитивным типом или ссылочным типом.
  • void не является допустимым типом значения.
  • Метод, объявленный с void возвращаемым типом, не возвращает значения.
  • Метод void run() не возвращает значение.
  • В run(), return без выражения успешно передает управление вызывающей стороне.
  • В run(), return some expression является ошибкой, поскольку some expression должно бытьдопустимое значение и run() не возвращает значение.
2 голосов
/ 17 октября 2011

return x явно означает «вернуть значение x», независимо от того, что это за тип (тип, конечно, все равно должен соответствовать типу возврата любой функции, в которую помещен этот оператор).

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

1 голос
/ 18 октября 2011

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

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

1 голос
/ 17 октября 2011

из JLS:

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

...

Оператор возврата с выражением должен содержаться в методе объявление, которое объявлено для возврата значения или времени компиляции ошибка происходит. Выражение должно обозначать переменную или значение некоторого типа T, или происходит ошибка времени компиляции. Тип T должен быть назначаемым к объявленному типу результата метода или ошибке времени компиляции происходит.

...