Почему локальные переменные, включая примитивы, всегда должны быть инициализированы в Java?

Почему локальные переменные, включая примитивы, всегда должны быть инициализированы в Java? Почему то же самое не применимо в случае переменных экземпляра?

7 ответов


было вопрос об этом совсем недавно для C#... - почитайте там ответы, так как это в основном то же самое. Вы также можете найти недавнее сообщение в блоге Эрика Липперта интересно; это, по крайней мере, вокруг той же области, хотя она имеет несколько другую тягу.

в принципе, требование присвоения переменной значения перед чтением-это хорошо. Это означает, что вы не будете случайно читать то, что вы не намеревались. Да, переменные могут иметь значения по умолчанию - но не лучше ли компилятору вместо этого поймать вашу ошибку, если она может доказать, что вы пытаетесь прочитать что-то, что, возможно, еще не было назначено? Если вы хотите дать локальной переменной значение по умолчанию, вы всегда можете назначить это явно.

теперь это нормально для локальных переменных - но, например, и статических переменных, компилятор не может знать порядок, в котором будут вызываться методы. Будет ли свойство "setter" звонили перед "добытчиком"? Он не знает, так что не предупреждая вас об опасности. Вот почему значения по умолчанию are используется, например, / статические переменные - по крайней мере, тогда вы получите известное значение (0, false, null и т. д.), а не просто "все, что случилось в памяти в то время."(Это также устраняет потенциальную проблему безопасности чтения конфиденциальных данных, которые не были явно стерты.)


Ну, в случае локальной переменной ясно, что это означает "до", так как поток программы между объявлением (в методе) и ссылкой является последовательным. В случае полей, объявленных вне метода, компилятор никогда не знает, какой код будет использоваться, поэтому он не может генерировать ошибку, поскольку, возможно, какой-то другой метод собирается инициализировать поле перед его использованием.


в Java переменные класса и экземпляра принимают значение по умолчанию (null, 0, false), если они не инициализированы вручную. Однако локальные переменные не имеют значения по умолчанию. Если локальной переменной не присвоено значение, компилятор откажется компилировать код, который ее читает. IMHO, это приводит к выводу, что инициализация локальной переменной с некоторым значением по умолчанию (например, null, что может привести к NullPointerException позже), когда она объявлена, на самом деле плохая вещь. Рассмотрим следующий пример:

Object o;
if (<some boolean condition>)
  o = <some value>;
else
  o = <some other value>;
System.out.println(o);

инициализацию o С null совершенно не нужно, так как компилятор Java проверяет во время компиляции, что любой путь кода инициализирует o (С нулевым или некоторым ненулевым значением) перед чтением переменной. Это означает, что компилятор откажется компилировать строку System.out.println(o); Если вы прокомментируете любую из двух инициализаций переменной o в приведенном выше фрагменте кода.

Это справедливо для Java, и, возможно, только для Java. Я не знаю о языке как C#. Однако в старом добром C (и, возможно, C++) по-прежнему рекомендуется всегда инициализировать переменные при их объявлении, AFAIK. Такие" олдскульные " языки программирования могут быть причиной того, что рекомендация всегда инициализировать переменные появляется в книгах и обсуждениях о современных языках, таких как Java, где компиляция отслеживает, была ли переменная инициализирована или нет.


Не совсем так. Локальные переменные должны быть инициализированы только в случае ссылки. Локальную переменную можно оставить неинициализированной, если на нее никогда не ссылаться. Например:

int x;  // Valid
int y;
println("y=" + y);  // Not valid since y's value has never been assigned

локальные переменные и примитивы должны быть инициализированы перед использованием, потому что вы знаете, чего ожидать от значений. Исторически сложилось так, что при создании новой переменной она будет содержать случайные значения из памяти [и невозможно предсказать значение]. Java также требует этого, потому что это предотвращает наличие потерянных переменных.


на практике все переменные должны быть инициализированы перед использованием их.

Я не могу придумать время, когда вы хотели бы использовать переменную перед установкой ее значения (если вы не сравниваете ее с null).


необходимо инициализировать локальные переменные (только когда мы их используем), потому что они не получают значения по умолчанию, такие как переменные экземпляра.

и как правило, мы всегда должны инициализировать переменную перед ее использованием. В противном случае это может привести к ошибке, такой как nullPointer и т. д.

теперь, почему локальные переменные не получают значение по умолчанию? Причина в том, что локальные переменные находятся в стеке и видны только в контексте локального метода, в отличие от переменных экземпляра, которые находится в куче и имеет область действия по всей программе.

поэтому, когда стек завершит значение локального метода, также будет уничтожено: 1] они должны быть инициализированы явно (когда мы их используем) 2] они не должны инициализироваться неявно (по null, 0 или false), как переменные экземпляра