Компилятор говорит: "Переменная может не быть инициализирована", хотя у меня есть переменная флага, чтобы гарантировать ее
Вот мой фрагмент кода:
Someclass someObject;
boolean success = true;
try {
someObject = someOperation();
} catch (Exception e) {
success = false;
}
if (success) {
int number = Integer.valueOf(someObject.someMethord());
}
и внутри строки:
int number = Integer.valueOf(someObject.someMethord());
выскакивает компилятор Java и говорит об ошибке
Ошибка: переменная someObject, возможно, не была инициализирована`.
Однако, если success
равно true
, тогда нет способа someObject
не инициализироваться, почему я получаю эту ошибку?
Ответы
Ответ 1
Компилятор не анализирует связь между вашим флагом success
и инициализацией переменной someObject
.
Что касается компилятора, someObject
может не инициализироваться, если возникает исключение.
Вы можете решить эту проблему, установив переменную в null
в вашем блоке catch (и вместо проверки вашей переменной success
убедитесь, что someObject != null
).
Или вы можете переместить оператор int number = Integer.valueOf(someObject.someMethord());
внутри блока try.
Ответ 2
Спецификация языка Java (JLS) точно определяет, как компилятор должен анализировать такой код.
В вашем случае локальная переменная someObject
не является определенно назначенной, прежде чем она будет использоваться в блоке if
. Определенное назначение, описанное в главе 16 JLS, определяет точные правила, по которым переменная может считаться назначенной ( "initialized" ).
Он анализирует операторы try
и if
отдельно. После try
, someObject
определенно не назначается, потому что он не назначен в блоке catch
. В if
условие может быть true
или false
. Если это было true
, вы получите сообщение об ошибке, потому что someObject
не определенно назначено в этот момент.
Компилятор Java не разрешен, чтобы проанализировать этот код и "выяснить", что success
может быть истинным, только если if someObject
, потому что в языковых правилах предписывается точный анализ, который должен выполняться. Это не случай, когда компилятор недостаточно интеллектуальный - это случай, когда стандарт языка Java является строгим.
Обратите внимание: если вы используете if(false)
вместо if(success)
, вы не получите ошибку, потому что JLS указывает, что false
является константным выражением и, следовательно, тело цикла никогда не будет выполняться.
Переменная флага в любом случае не нужна. Перемещение зависимого кода в try
или установка переменной в null
в декларации и явная проверка на someObject != null
- это все подходы, которые проще понять и гораздо менее подвержены ошибкам.
Ответ 3
Вы можете изменить свое объявление следующим образом:
Someclass someObject = null;
Или вы можете сделать все в try-catch, чтобы убедиться, что someObject
будет правильно инициализирован
try {
Someclass someObject = someOperation();
int number = Integer.valueOf(someObject.someMethod());
} catch (Exception e) {
//...
}
Ответ 4
Компилятор делает только очень тривиальный статический анализ и по дизайну. Статический анализ может стать более умным с течением времени, и вы наверняка не захотите, чтобы код прекратил компиляцию при переключении на более старую версию компилятора.
Другая причина заключается в том, что компилятор работает быстро. Умный анализ важен для оптимизации, но его "дорого". Оптимизация - это не работа javac
(они происходят во время выполнения), поэтому javac
не беспокоит.
Он даже не распознает тривиальные случаи, такие как
int f(boolean b) {
if (b) {
return 1;
} else if (!b) {
return 0;
}
}
Правила указаны в JLS Chapter Definite Assignment.
Ответ 5
Вы можете просмотреть этот сценарий как -
What happens is your try blocks fails to initialize the someObject.
Это означает, что может быть какое-то исключение в методе someOperation()
. Исключение будет обнаружено, но someObject
не будет инициализироваться.
Вы можете исправить это, установив someObject
в null или new SomeObject()
в блок catch.
Ответ 6
То, что вы описываете в Java, очень похоже на С# (там будет сообщение CS0165 Use of unassigned local variable 'someObject'
). Решение на обоих языках состоит в создании нулевого присвоения:
SomeClass someObject = null;
и предупреждение исчезнет. Как описывали другие ответы, причина в том, что компилятор недостаточно умен, поэтому эти предупреждения являются своего рода компромиссом.
Пример Java:
class SomeClass
{
public int someMethod()
{
return 1;
}
}
public class JavaFiddle
{
public static SomeClass someOperation()
{
SomeClass result = new SomeClass();
return result;
}
public static void main(String[] args)
{
SomeClass someObject = null;
boolean success = true;
try {
someObject = someOperation();
} catch (Exception e) {
success = false;
}
if (success) {
int number = Integer.valueOf(someObject.someMethod());
}
}
}
Вставьте этот код в JavaFiddle
(нажмите Ctrl и left-click, чтобы открыть вкладку с JavaFiddle)
> Компиляция...
> Запуск...
Как вы можете видеть, в приведенном выше коде проблема уже исправлена, поэтому, если вы вставляете ее в инструмент JavaFiddle, она будет работать как ожидалось без ошибок.
Чтобы спровоцировать ошибку, измените код следующим образом:
SomeClass someObject; // = null;
и запустите его снова. Вы получите сообщение:
> Компиляция...
/str/JavaFiddle.java:29: ошибка: переменная someObject, возможно, не была инициализирована
int number = Integer.valueOf(someObject.someMethod());
^
1 ошибка
Примечание, что я только что привел пример, который вы предоставили "как есть" - вы должны рассмотреть намеки, касающиеся обработки исключений (см. комментарий к вашему вопросу от Эрика Липперта). Проглатывание исключений, не обрабатывающих их, как правило, не очень хорошо - лучше справляйтесь с ситуациями, которые вы знаете в коде, и позвольте вызывающему агенту обрабатывать любые исключения, которые могут возникнуть, о которых вы не знаете (и, конечно же, реализуете некоторые протоколирования).
Ответ 7
компилятор имеет ограниченное представление о том, что может иметь эта переменная, например:
public void test() {
int y = 2;
Integer x;
if (y == 2) {
x = 2;
}
System.out.println(x);// this will fail
}
Но сделайте это final y = 2
, и компилятор увидит, что в этом случае единственное возможное значение y
равно 2.