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

boolean method(int value) {
    switch(value) {
    case 0:
        return false;
    case 1:
        return true;
    default:
        Assert.fail("Unhandled value.");
    }
}

Компиляция завершается сбоем с ошибкой «Метод должен возвращать результат», хотя Assert.fail() ничего не делает, кроме как выдает AssertionError. Если я сам выброшу AssertionError вместо вызова Assert.fail(), он скомпилируется.


person Monstieur    schedule 25.04.2014    source источник
comment
только вы знаете, что Assert.fail() выдает AssertionError. Компилятор тоже это знает?   -  person TheLostMind    schedule 25.04.2014


Ответы (3)


Компилятор не может знать, что Assert.fail всегда будет генерировать исключение, если только он не углубится в байт-код этого метода и не проведет над ним своего рода статический анализ (и как только вы запустите такого рода вещь, то где вы останавливаетесь?). В спецификации языка Java указано (раздел 8.4.7)

Если объявлен метод с возвращаемым типом, то возникает ошибка времени компиляции, если тело метода может завершиться нормально (§14.1).

где "может завершиться нормально" в вашем примере сводится к (раздел 14.21)

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

Последний оператор в вашем методе — это оператор switch:

Оператор switch может завершиться нормально, если верно хотя бы одно из следующего:

[...]

  • Последний оператор в блоке switch может завершиться нормально.

Последний оператор в switch — это оператор-выражение (вызов метода).

Оператор выражения может завершиться нормально, если он достижим.

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

В этом же разделе также определяется, что

Оператор break, continue, return или throw не может нормально завершиться.

Поэтому, чтобы компилятор был доволен, вам нужно добавить return или throw в конец метода.

// will never be reached
throw new Error();

Я бы лично пошел на бросок с комментарием, объясняющим, что что-то пошло не так, если эта линия когда-либо будет достигнута...

person Ian Roberts    schedule 25.04.2014
comment
Но это происходит, даже когда я использую закрытый метод в том же классе, что и throws. В этом случае он может полностью видеть исходный код. - person Monstieur; 25.04.2014
comment
@Locutus, тем не менее, Спецификация языка Java предписывает, что компилятор не должен заглядывать внутрь вызовов методов и должен предполагать, что любой вызов метода может завершиться нормально. - person Ian Roberts; 25.04.2014

Компилятор не может знать, что Assert.fail() будет всегда генерировать исключение, поэтому компилятору по-прежнему требуется оператор return (или явный throw, как предлагается Иэн Робертс). Когда вы явно кодируете throw new AssertionError(), компилятор точно знает, что закрытие } метода не может быть достигнуто, а return не требуется.

person hmjd    schedule 25.04.2014
comment
Это правильный ответ на вопрос ОП. +1.. :) - person TheLostMind; 25.04.2014

У вас всегда должно быть возвращаемое значение или исключение для всех путей кода. Компиляция не знает, что Assert.fail не всегда выдает исключение

person Leon    schedule 25.04.2014