L'idea alla base delle variabili locali è che esistono solo all'interno dell'ambito limitato per il quale sono necessarie. In quanto tale, dovrebbero esserci poche ragioni per incertezza sul valore, o almeno, da dove proviene tale valore. Potrei immaginare molti errori derivanti dall'avere un valore predefinito per le variabili locali.
Ad esempio, si consideri il seguente codice semplice ... ( NB si supponga a scopo dimostrativo che alle variabili locali venga assegnato un valore predefinito, come specificato, se non esplicitamente inizializzato )
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);
Quando tutto è stato detto e fatto, supponendo che il compilatore abbia assegnato un valore predefinito di '\ 0' a letterGrade , questo codice come scritto funzionerebbe correttamente. Tuttavia, cosa succede se dimentichiamo la dichiarazione else?
Un'esecuzione di prova del nostro codice potrebbe comportare quanto segue
Enter grade
43
Your grade is
Questo risultato, sebbene prevedibile, non era sicuramente l'intento del programmatore. In effetti, probabilmente nella stragrande maggioranza dei casi (o almeno in un numero significativo), il valore predefinito non sarebbe il valore desiderato , quindi nella stragrande maggioranza dei casi il valore predefinito risulterebbe in errore. Ha più senso forzare il programmatore ad assegnare un valore iniziale a una variabile locale prima di usarla, poiché il problema di debug causato dalla dimenticanza di = 1
in for(int i = 1; i < 10; i++)
supera di gran lunga la comodità di non dover includere = 0
in for(int i; i < 10; i++)
.
È vero che i blocchi try-catch-latest potrebbero diventare un po 'confusi (ma in realtà non è un catch-22 come sembra suggerire la citazione), quando ad esempio un oggetto lancia un'eccezione controllata nel suo costruttore, ma per uno motivo o un altro, qualcosa deve essere fatto a questo oggetto alla fine del blocco alla fine. Un perfetto esempio di questo è quando si tratta di risorse, che devono essere chiuse.
Un modo per gestire questo problema in passato potrebbe essere così ...
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();
}
Tuttavia, a partire da Java 7, questo blocco finalmente non è più necessario utilizzando try-with-resources, in questo modo.
try (Scanner s = new Scanner(new FileInputStream(new File("filename.txt")))) {
...
...
} catch(IOException e) {
System.out.println("different error message");
}
Detto questo, (come suggerisce il nome) funziona solo con le risorse.
E mentre il primo esempio è un po 'schifoso, questo forse parla più del modo in cui try-catch-infine o queste classi sono implementate che non delle variabili locali e di come sono implementate.
È vero che i campi vengono inizializzati su un valore predefinito, ma questo è leggermente diverso. Quando dici, ad esempio, int[] arr = new int[10];
non appena hai inizializzato questo array, l'oggetto esiste in memoria in una data posizione. Supponiamo per un momento che non ci siano valori predefiniti, ma invece il valore iniziale è qualsiasi serie di 1 e 0 si trovi in quella posizione di memoria al momento. Ciò potrebbe portare a comportamenti non deterministici in un certo numero di casi.
Supponiamo di avere ...
int[] arr = new int[10];
if(arr[0] == 0)
System.out.println("Same.");
else
System.out.println("Not same.");
Sarebbe perfettamente possibile che Same.
potrebbe essere visualizzato in una corsa e Not same.
potrebbe essere visualizzato in un'altra. Il problema potrebbe diventare ancora più grave una volta che inizi a parlare di variabili di riferimento.
String[] s = new String[5];
Secondo la definizione, ogni elemento di s dovrebbe puntare a una stringa (o è nullo). Tuttavia, se il valore iniziale è una qualsiasi serie di 0 e 1 che si verifica in questa posizione di memoria, non solo non c'è garanzia che otterrai gli stessi risultati ogni volta, ma non c'è neppure alcuna garanzia che l'oggetto s [0] punti a (supponendo che punti a qualcosa di significativo) anche è una stringa (forse è un coniglio,: p )! Questa mancanza di attenzione per il tipo andrebbe contro praticamente tutto ciò che rende Java Java. Quindi, mentre avere valori di default per le variabili locali potrebbe essere visto come facoltativo nel migliore dei casi, avere valori di default per le variabili di istanza è più vicino a una necessità .