Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/variables/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么Java中没有初始化局部变量?_Java_Variables_Initialization - Fatal编程技术网

为什么Java中没有初始化局部变量?

为什么Java中没有初始化局部变量?,java,variables,initialization,Java,Variables,Initialization,Java的设计者为什么认为不应该给局部变量一个默认值?说真的,如果可以给实例变量一个默认值,那么为什么我们不能对局部变量也这样做呢 这也会导致如下所述的问题: 当试图关闭finally块中的资源时,这个规则最令人沮丧。如果我在try中实例化资源,但在finally中尝试关闭它,则会出现此错误。如果将实例化移到try之外,则会出现另一个错误,指出它必须在try内 非常令人沮丧 我认为主要目的是保持与C/C++的相似性。但是,编译器会检测并警告您不要使用未初始化的变量,这会将问题减少到最小程度。从性

Java的设计者为什么认为不应该给局部变量一个默认值?说真的,如果可以给实例变量一个默认值,那么为什么我们不能对局部变量也这样做呢

这也会导致如下所述的问题:

当试图关闭finally块中的资源时,这个规则最令人沮丧。如果我在try中实例化资源,但在finally中尝试关闭它,则会出现此错误。如果将实例化移到try之外,则会出现另一个错误,指出它必须在try内

非常令人沮丧


我认为主要目的是保持与C/C++的相似性。但是,编译器会检测并警告您不要使用未初始化的变量,这会将问题减少到最小程度。从性能角度来看,声明未初始化的变量要快一点,因为编译器不必编写赋值语句,即使您在下一个语句中覆盖变量的值。

声明局部变量主要是为了进行一些计算。因此,设置变量的值是程序员的决定,它不应该采用默认值


如果程序员错误地没有初始化局部变量,并且它采用了默认值,那么输出可能是一些意外值。因此,对于局部变量,编译器将要求程序员在访问变量之前使用一些值对其进行初始化,以避免使用未定义的值。

请注意,默认情况下不会初始化最终实例/成员变量。因为这些都是最终的,以后不能在程序中更改。这就是Java没有为它们提供任何默认值并强制程序员对其进行初始化的原因

另一方面,非最终成员变量可以稍后更改。因此,编译器不会让它们保持未初始化状态,因为它们可以在以后更改。关于局部变量,局部变量的范围要窄得多。编译器知道何时使用它。因此,强制程序员初始化变量是有意义的。

似乎在描述这种情况:

SomeObject so;
try {
  // Do some work here ...
  so = new SomeObject();
  so.DoUsefulThings();
} finally {
  so.CleanUp(); // Compiler error here
}
评论者的抱怨是,编译器在
finally
部分的那一行犹豫不决,声称
so
可能未初始化。然后,注释提到了编写代码的另一种方式,可能类似于:

// Do some work here ...
SomeObject so = new SomeObject();
try {
  so.DoUsefulThings();
} finally {
  so.CleanUp();
}
评论者对该解决方案不满意,因为编译器接着说代码“必须在一次尝试中”。我猜这意味着一些代码可能会引发一个不再处理的异常。我不确定。我的代码的两个版本都不处理任何异常,因此第一个版本中与异常相关的任何异常在第二个版本中都应该工作相同

无论如何,第二个版本的代码是正确的编写方法。在第一个版本中,编译器的错误消息是正确的。
so
变量可能未初始化。特别是,如果
SomeObject
构造函数失败,
so
将不会初始化,因此尝试调用
so.CleanUp
将是一个错误。在获得
部分最终完成的资源后,始终输入
try
部分

try
-
finally
块位于
之后,因此
初始化仅用于保护
SomeObject
实例,以确保无论发生什么情况,它都会被清除。如果还有其他东西需要运行,但它们与
SomeObject
实例是否分配了属性无关,那么它们应该进入另一个
try
-
finally
块,可能是一个包装了我所展示的块的块

要求在使用前手动分配变量不会导致真正的问题。这只会带来一些小麻烦,但您的代码会因此变得更好。您将拥有范围更为有限的变量,
try
-
最后,
块不会试图保护太多


如果局部变量有默认值,那么第一个示例中的
so
应该是
null
。这并不能解决任何问题。与在
finally
块中获得编译时错误不同,您将有一个
NullPointerException
潜伏在那里,它可能会隐藏代码“Dosomeworkhere”部分中可能发生的任何其他异常。(或者,
最后
部分中的异常会自动链接到前一个异常吗?我不记得了。即使如此,您也会有一个与实际异常相同的额外异常。)

Eclipse甚至会对未初始化的变量发出警告,所以不管怎样,它变得非常明显。我个人认为这是默认行为是件好事,否则应用程序可能会使用意外值,编译器不会抛出错误,它不会做任何事情(但可能会发出警告)然后,你会摸不着头脑,弄不明白为什么某些事情没有按应有的方式进行。

不初始化变量更有效,而在局部变量的情况下,这样做是安全的,因为编译器可以跟踪初始化


在需要初始化变量的情况下,您始终可以自己进行初始化,因此这不是问题。

此外,在下面的示例中,SomeObject构造中可能引发了异常,在这种情况下,“so”变量将为null,对CleanUp的调用将引发NullPointerException

SomeObject so;
try {
  // Do some work here ...
  so = new SomeObject();
  so.DoUsefulThings();
} finally {
  so.CleanUp(); // Compiler error here
}
我倾向于这样做:

SomeObject so = null;
try {
  // Do some work here ...
  so = new SomeObject();
  so.DoUsefulThings();
} finally {
  if (so != null) {
     so.CleanUp(); // safe
  }
}

局部变量存储在堆栈上,但实例变量存储在堆上,因此有可能读取堆栈上的前一个值,而不是堆中的默认值

因此,JVM不允许使用本地变量
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);
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();
}
try (Scanner s = new Scanner(new FileInputStream(new File("filename.txt")))) {
    ...
    ...
} catch(IOException e) {
    System.out.println("different error message");
}
int[] arr = new int[10];
if(arr[0] == 0)
    System.out.println("Same.");
else
    System.out.println("Not same.");
String[] s = new String[5];