局部变量背后的想法是它们只存在于需要它们的有限范围内。因此,对于该值,或者至少该值的来源,应该没有什么不确定性的理由。我可以想象由于局部变量具有默认值而引起的许多错误。
例如,考虑下面的简单代码...(注意,为了演示的目的,让我们假设局部变量被分配了一个默认值,如指定的,如果没有显式初始化)
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
这个结果虽然在意料之中,但肯定不是编码员的本意。实际上,可能在绝大多数情况下(或至少在相当多的情况下),默认值不会是 desired 值,因此在绝大多数情况下,默认值会导致错误。强制编码器在使用局部变量之前为其分配一个初始值更有意义,因为在for(int i = 1; i < 10; i++) 中忘记= 1 引起的调试痛苦远远超过了不必将= 0 包含在其中的便利性。 for(int i; i < 10; i++).
确实,try-catch-finally 块可能会有点混乱(但它实际上并不是引用似乎暗示的 catch-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 开始,使用 try-with-resources 不再需要这个 finally 块,就像这样。
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]; 时,一旦您初始化了这个数组,该对象就存在于内存中的给定位置。让我们暂时假设没有默认值,而是初始值是此时恰好在该内存位置中的任何 1 和 0 序列。在许多情况下,这可能会导致不确定的行为。
假设我们有...
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的每个元素都应该指向一个String(或者为null)。但是,如果初始值是在这个内存位置发生的任何一系列 0 和 1,不仅不能保证每次都会得到相同的结果,而且也不能保证对象 s[0] 指向到(假设它指向任何有意义的东西)甚至 is 一个字符串(也许它是一只兔子,:p)!面对几乎所有使 Java 成为 Java 的东西,这种对类型的缺乏关注会飞起来。因此,虽然为局部变量设置默认值充其量只能被视为可选,但为实例变量设置默认值更接近必需。