Методът трябва да върне резултат, когато извиква друг метод, който хвърля само изключение

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 е израз на израз (извикване на метод)

Инструкция за израз може да завърши нормално, ако е достъпна.

т.е. спецификацията изрично посочва, че компилаторът не трябва да търси вътре в никакви извиквания на метод и всеки израз за извикване на метод трябва да се счита за такъв, който може да завърши нормално.

Същият раздел също дефинира това

Оператор 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
Това е правилният отговор на въпроса на OP. +1.. :) - person TheLostMind; 25.04.2014

Винаги трябва да имате върната стойност или изключение за всички кодови пътеки. Компилацията не знае, че Assert.fail не винаги хвърля изключение

person Leon    schedule 25.04.2014