Идея локальных переменных заключается в том, что они существуют только в той ограниченной области, для которой они необходимы. Таким образом, не должно быть причин для неуверенности в отношении значения или, по крайней мере, того, откуда оно взято. Я мог представить себе множество ошибок, возникающих из-за значения по умолчанию для локальных переменных.
Например, рассмотрим следующий простой код ... ( NB давайте предположим, в демонстрационных целях, что локальным переменным присваивается значение по умолчанию, как указано, если не инициализировано явно )
System.out.println("Enter grade");
int grade = new Scanner(System.in).nextInt(); //I won't bother with exception handling here, to cut down on lines.
char letterGrade; //let us assume the default value for a char is '\0'
if (grade >= 90)
letterGrade = 'A';
else if (grade >= 80)
letterGrade = 'B';
else if (grade >= 70)
letterGrade = 'C';
else if (grade >= 60)
letterGrade = 'D';
else
letterGrade = 'F';
System.out.println("Your grade is " + letterGrade);
Когда все сказано и сделано, предполагая, что компилятор присвоил letterGrade значение по умолчанию '\ 0' , этот код в том виде, в каком он написан, будет работать правильно. Однако что, если мы забыли инструкцию else?
Тестовый запуск нашего кода может привести к следующему
Enter grade
43
Your grade is
Такой результат, хотя и ожидался, определенно не входил в намерения программиста. Действительно, вероятно, в подавляющем большинстве случаев (или, по крайней мере, в значительном их числе) значение по умолчанию не будет желаемым , поэтому в подавляющем большинстве случаев значение по умолчанию приведет к ошибке. Имеет смысл заставить кодировщик назначать начальное значение локальной переменной перед ее использованием, поскольку затруднения при отладке, вызванные забыванием = 1
in, for(int i = 1; i < 10; i++)
намного перевешивают удобство отсутствия необходимости включать = 0
in for(int i; i < 10; i++)
.
Это правда, что блоки try-catch-finally могут стать немного беспорядочными (но на самом деле это не уловка-22, как кажется в цитате), когда, например, объект выдает проверенное исключение в своем конструкторе, но для одного по какой-либо причине, что-то должно быть сделано с этим объектом в конце блока в finally. Прекрасный пример этого - работа с ресурсами, которые необходимо закрыть.
Один из способов справиться с этим в прошлом мог быть таким ...
Scanner s = null; //declared and initialized to null outside the block. This gives us the needed scope, and an initial value.
try {
s = new Scanner(new FileInputStream(new File("filename.txt")));
int someInt = s.nextInt();
} catch (InputMismatchException e) {
System.out.println("Some error message");
} catch (IOException e) {
System.out.println("different error message");
} finally {
if (s != null) //in case exception during initialization prevents assignment of new non-null value to s.
s.close();
}
Однако, начиная с Java 7, этот блок finally больше не нужен с использованием try-with-resources, например.
try (Scanner s = new Scanner(new FileInputStream(new File("filename.txt")))) {
...
...
} catch(IOException e) {
System.out.println("different error message");
}
Тем не менее (как следует из названия) это работает только с ресурсами.
И хотя первый пример немного неприятен, это, возможно, больше говорит о способе реализации try-catch-finally или этих классов, чем о локальных переменных и о том, как они реализованы.
Это правда, что поля инициализируются значением по умолчанию, но это немного другое. Когда вы говорите, например, int[] arr = new int[10];
как только вы инициализировали этот массив, объект существует в памяти в заданном месте. Предположим на мгновение, что нет значений по умолчанию, но вместо этого начальное значение - это любая последовательность единиц и нулей, которая в данный момент находится в этой ячейке памяти. В ряде случаев это может привести к недетерминированному поведению.
Предположим, у нас есть ...
int[] arr = new int[10];
if(arr[0] == 0)
System.out.println("Same.");
else
System.out.println("Not same.");
Вполне возможно, что это Same.
может отображаться в одном прогоне и Not same.
может отображаться в другом. Проблема может стать еще более серьезной, если вы начнете говорить о ссылочных переменных.
String[] s = new String[5];
Согласно определению, каждый элемент s должен указывать на строку (или иметь значение NULL). Однако, если начальным значением является любая последовательность нулей и единиц, встречающаяся в этой ячейке памяти, не только нет гарантии, что вы будете каждый раз получать одни и те же результаты, но также нет гарантии, что объект s [0] указывает to (при условии, что он указывает на что-нибудь значимое) даже является String (возможно, это Rabbit,: p )! Это отсутствие заботы о типе противоречит почти всему, что делает Java Java. Таким образом, хотя значения по умолчанию для локальных переменных можно рассматривать в лучшем случае как необязательные, наличие значений по умолчанию для переменных экземпляра ближе к необходимости .