Почему этот код неправильный? Когда я изменяю "else if(this.power >= p)"
только в "else"
, это правильно. Может ли кто-нибудь дать мне подсказку?
public boolean useBattery(double p) {
if(this.power < p) {
this.power = 0.0;
return false;
} else if(this.power >= p) {
this.power = this.power - p;
return true;
}
}
Для читателя-человека, смотрящего на код, кажется, что либо первое return
будет удалено, либо второе, но компилятор не может быть уверен. Для компилятора это выглядит так:
if (condition1) {
...
return false;
} else if (condition2) {
...
return true;
}
и он должен знать, что будет возвращать метод, если ни condition1
ни condition2
являются истинными?
Если вы измените его на else
,
if (condition1) {
...
return false;
} else {
...
return true;
}
то несомненно, что одно из двух return
операторов должно быть удалено.
Фактически в вашем методе есть вероятность, что ни одно условие не будет выполнено: если один из чисел, которые вы сравниваете, - NaN
(специальное значение с плавающей запятой, представляющее "не число"), тогда оба ваших условия if
будут ложными, и метод не будет иметь возвращаемого значения.
Существует также теоретически возможность того, что некоторый код, запущенный в другом потоке, может изменить значение this.power
между первым, if
проверить, и вторым, что может привести к тому, что оба условия оцениваются как false. Поэтому компилятор не может точно знать, что одно из условий будет выполнено, даже если они логически дополняют друг друга.
Что произойдет, если мы не войдем в ваши условные ветки? Java не может определить, что вы сможете, потому что else if
подразумевается, что не может быть другой условной ветки для проверки.
Выписано другим способом, есть неявный блок else
, который ничего не делает. Поскольку вы объявляете тип возврата, наличие этого неявного блока else
ничего не представляет собой ошибку.
Блок else
всегда гарантированно исполняется, поэтому вы не столкнетесь с той же ситуацией с else
, что, вероятно, является тем, что вы намеревались использовать в первую очередь.
Подумайте в случае блок-схемы.
this.power < p
), то power
на 0this.power >= p
если (this.power >= p
), то p
из power
Потому что, если вы добавите, если во втором случае может существовать условие, при котором ни одно из условий не будет выполнено, а метод не будет соответствовать возврату.
Рассмотрим этот простой пример:
Рассмотрим x = 5; ниже код не будет соответствовать запросу return, потому что он не удовлетворяет никакому условию.
if(x>5){
return true;
}
else if(x < 5){
return false;
}
Вы можете воспроизвести эту ошибку с еще более коротким кодом:
public int doSomething() {
if(true) {
return 0;
}
}
Этот метод генерирует ошибку компилятора missing return statement
Компилятор не выполняет интеллектуальный статический анализ вашего кода. Он просто проверяет утверждения в соответствии со спецификацией.
Спецификация языка Java 8.4.7 "Тело метода" гласит, что:
Если объявлен метод с типом возвращаемого значения, тогда возникает ошибка времени компиляции, если тело метода может завершиться нормально.
Таким образом, компилятор просто проверяет, могут ли эти операторы нормально работать.
JLS 14.9.1 "Заявление if-then":
Если значение истинно, то выполняется исполняемый оператор; инструкция if-then выполняется нормально тогда и только тогда, когда выполнение Statement завершается нормально.
Если значение равно false, никаких дальнейших действий не предпринимается, и инструкция if-then выполняется нормально.
Как вы можете видеть по спецификации, если оператор может завершиться нормально. Вот почему возникает ошибка времени компиляции.
С другой стороны, JLS 14.9.2 "Заявление if-then-else":
Если значение истинно, тогда выполняется первый содержащийся оператор (один до ключевого слова else); оператор if-then-else обычно заканчивается тогда и только тогда, когда выполнение этого оператора завершается нормально.
Если значение равно false, тогда выполняется второй оператор (один после ключевого слова else); оператор if-then-else обычно заканчивается тогда и только тогда, когда выполнение этого оператора завершается нормально.
Как вы можете видеть, если-then-else завершается тогда и только тогда, когда один из его блоков завершается нормально. В вашем примере оба из них содержат операторы return.
return
как последний оператор в вашем методе, избегайте использования нескольких операторовreturn
каждой ветви.