Ideą zmiennych lokalnych jest to, że istnieją one tylko w ograniczonym zakresie, dla którego są potrzebne. W związku z tym nie powinno być powodów do niepewności co do wartości lub przynajmniej skąd ta wartość pochodzi. Mogłem sobie wyobrazić wiele błędów wynikających z posiadania domyślnej wartości dla zmiennych lokalnych.
Na przykład rozważmy następujący prosty kod ... ( Uwaga: załóżmy dla celów demonstracyjnych, że zmiennym lokalnym przypisywana jest wartość domyślna, jak określono, jeśli nie została ona jawnie zainicjowana )
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);
Kiedy wszystko jest powiedziane i zrobione, zakładając , że kompilator przypisał domyślną wartość „\ 0” do letterGrade , ten kod, tak jak napisano, działałby poprawnie. A co by było, gdybyśmy zapomnieli o stwierdzeniu else?
Uruchomienie testowe naszego kodu może spowodować następujące skutki
Enter grade
43
Your grade is
Taki wynik, choć można się było spodziewać, z pewnością nie był zamiarem programisty. Rzeczywiście, prawdopodobnie w zdecydowanej większości przypadków (lub przynajmniej w znacznej ich liczbie) wartość domyślna nie byłaby wartością pożądaną , więc w zdecydowanej większości przypadków wartość domyślna powodowałaby błąd. Bardziej sensowne jest wymuszenie na koderze przypisania wartości początkowej do zmiennej lokalnej przed jej użyciem, ponieważ problemy związane z debugowaniem spowodowane zapomnieniem o = 1
in for(int i = 1; i < 10; i++)
znacznie przewyższają wygodę związaną z brakiem konieczności dołączania = 0
in for(int i; i < 10; i++)
.
Prawdą jest, że bloki try-catch-final mogą się trochę zabrudzić (ale tak naprawdę nie jest to catch-22, jak wydaje się sugerować cytat), gdy na przykład obiekt zgłasza sprawdzony wyjątek w swoim konstruktorze, ale dla jednego czy z innego powodu, na końcu bloku trzeba coś zrobić z tym obiektem. Doskonałym tego przykładem jest sytuacja z zasobami, które należy zamknąć.
Jednym ze sposobów radzenia sobie z tym w przeszłości może być taki ...
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();
}
Jednak od wersji Java 7 ta ostateczna blokada nie jest już konieczna przy użyciu zasobów próbnych.
try (Scanner s = new Scanner(new FileInputStream(new File("filename.txt")))) {
...
...
} catch(IOException e) {
System.out.println("different error message");
}
To powiedziawszy (jak sugeruje nazwa) działa to tylko z zasobami.
I chociaż poprzedni przykład jest trochę obrzydliwy, to prawdopodobnie bardziej mówi o sposobie implementacji try-catch-final lub tych klas niż o zmiennych lokalnych i ich implementacji.
Prawdą jest, że pola są inicjowane do wartości domyślnej, ale jest to trochę inne. Kiedy mówisz, na przykład, int[] arr = new int[10];
gdy tylko zainicjujesz tę tablicę, obiekt istnieje w pamięci w podanej lokalizacji. Załóżmy na chwilę, że nie ma wartości domyślnych, ale zamiast tego wartość początkowa jest dowolną serią jedynek i zer, która znajduje się w danej chwili w tej lokalizacji pamięci. W wielu przypadkach może to prowadzić do niedeterministycznych zachowań.
Załóżmy, że mamy ...
int[] arr = new int[10];
if(arr[0] == 0)
System.out.println("Same.");
else
System.out.println("Not same.");
Byłoby całkowicie możliwe, że Same.
mogłoby to zostać wyświetlone w jednym przebiegu i Not same.
w innym. Problem może stać się jeszcze poważniejszy, gdy zaczniesz mówić o zmiennych referencyjnych.
String[] s = new String[5];
Zgodnie z definicją, każdy element s powinien wskazywać na String (lub jest pusty). Jeśli jednak wartość początkowa jest dowolną serią 0 i 1, która zdarzy się w tej lokalizacji pamięci, nie tylko nie ma gwarancji, że za każdym razem otrzymasz te same wyniki, ale także nie ma gwarancji, że obiekt s [0] wskazuje to (zakładając, że wskazuje na coś znaczącego) nawet jest Stringiem (być może jest to Królik,: p )! Ten brak troski o typ byłby sprzeczny z prawie wszystkim, co czyni Java Java. Tak więc, chociaż posiadanie wartości domyślnych dla zmiennych lokalnych może być w najlepszym przypadku postrzegane jako opcjonalne, posiadanie wartości domyślnych, na przykład zmiennych, jest bliższe konieczności .