Явное "пустое конечное поле", возможно, не было инициализировано "Исключение, вызванное нечетностью метода
У меня есть код вроде:
final int var1;
if ( isSomethingTrue ) {
var1 = 123;
} else {
throwErrorMethod();
}
int var2 = var1;
И throwErrorMethod определяется примерно так:
private void throwErrorMethod() throws Exception{
throw new Exception();
}
И я получаю компиляцию blank final field may not have been initialized
для оператора var2 = var1
. Если я встраиваю метод, компиляция в порядке!
- Разве компилятор не видит
throws Exception
в методе, который называется?
- Почему ошибка, которая содержит слово
may
в ней, останавливает компиляцию?!?
Ответы
Ответ 1
-
Нет, компилятор не определяет, что throwErrorMethod
никогда не завершится нормально. В спецификации нет ничего, что можно было бы предложить. К сожалению, нет способа указать, что метод никогда не будет нормально возвращаться.
-
Он только "может", потому что существует потенциальный путь выполнения, который не инициализирует переменную. Наличие такого пути выполнения определяется как ошибка.
Вы можете найти эту пару сообщений в блоге (часть 1; часть 2) от Эрика Липперта. Это о С#, а не Java, но это тот же принцип.
Ответ 2
Исключения должны быть исключительными. Он не предполагает, что исключение всегда выбрасывается.
Компилятор использует слово may
, поскольку он не может определить, можете ли вы получить доступ к неинициализированной переменной. Кроме того, вы можете изменить, что делает этот метод, не перекомпилировав этот класс, и любое допущение, которое оно сделало, было бы неверным.
Если вы хотите всегда выкидывать исключение, вы можете сделать
final int var1;
if ( isSomethingTrue ) {
var1 = 123;
} else {
throw exceptionMethod();
}
int var2 = var1;
// later
public Exception exceptionMethod() {
return new Exception("Complex-Exception-String");
}
Ответ 3
Компилятор не выполняет такую проверку, которую вы ожидаете. Он не уверен, что throwErrorMethod
действительно генерирует исключение каждый раз. Поэтому он предполагает, что можно перейти в ваше предложение else
, вызвать throwErrorMethod
, возврат из этого метода, а затем не инициализировать var1
(который должен быть инициализирован).
Ответ 4
Если вы хотите сообщить компилятору, что ошибка определенно будет выбрана, но не хотите вставлять логику для построения ошибки, вы можете сделать что-то вроде этого:
} else {
throw createErrorMethod();
}
где createErrorMethod()
объявляется как возвращающий некоторый тип Throwable.
Ответ 5
Метод, объявленный "throws Exception", не должен бросать это исключение в любой путь выполнения. Поэтому компилятор не знает, будет ли исключение исключаться методом и предполагает также нормальное завершение. Таким образом, может быть, что var1
не инициализируется.