为什么编译器会说如果变量需要在循环中才能通过,则可能不会对其进行初始化?
Why does the compiler say a variable might not be initialized if it's required to be during a loop for it to pass?
我正在编写一个程序来计算用户定义整数中偶数、奇数和零的数量。奇怪的是,编译器根本不会编译。它说 "error: variable number might not have been initialized".
没有意义的是,据我所知,这个循环将保证 number
始终被初始化。我知道我可以通过在声明处初始化来轻松关闭编译器。我总是被告知,尽管在声明时初始化以帮助避免逻辑错误通常不是一个好主意。然而我最大的 scare/confusion 是我不知道为什么它不喜欢它。如果有异常,它会在 validInput = true
发生之前被捕获,不是吗?因此,当循环进行检查时,它将重新启动,因为 validInput
仍将是 false
。这甚至不是警告或任何东西;这是一个硬停止错误。我错过或没有看到什么?
我读过其他有关 if-checks 的案例,这与可能通过或可能不通过的检查不同。这个循环最终总是会通过,除非程序以某种方式提前退出(在这种情况下它无论如何都不会到达 for 循环)。如果这是重复的,有人可以指出我找不到的直接相关答案吗?谢谢!
public static void main( String[] args )
{
long number;
boolean validInput = false;
String numStr;
Scanner input = new Scanner(System.in);
do
{
System.out.print("Please enter an integer: ");
numStr = input.next();
try {
number = Long.parseLong(numStr);
validInput = true;
} catch (NumberFormatException e) {
System.out.print("That's not an integer. ");
}
} while (!validInput);
// Break each digit up by dividing by powers of 10.
int evens = 0, odds = 0, zeros = 0;
for (long temp = number; temp > 0; temp /= 10)
{
int digit = (int)(temp % 10);
if (digit == 0)
{
zeros++;
System.out.println(digit + " is a zero digit.");
}
else if (digit % 2 == 0)
{
evens++;
System.out.println(digit + " is an even digit.");
}
else
{
odds++;
System.out.println(digit + " is an odd digit.");
}
}
String evenStr = " even " + ((evens == 1) ? "digit" : "digits");
String oddStr = " odd " + ((odds == 1) ? "digit" : "digits");
String zeroStr = (zeros == 1) ? " zero" : " zeros";
System.out.println(number + " has " + evens + evenStr + ", " + odds + oddStr + ", and "
+ zeros + zeroStr + ".");
}
你是对的,number
永远不会因为你在 validInput
上的条件而逃脱你的未初始化循环。但是编译器不够聪明,无法弄清楚整个逻辑并确定它是安全的。它所看到的只是这一行位于 try-catch
块内,该块可能会或可能不会引发异常:
number = Long.parseLong(numStr);
...因此它看到 潜在 变量 number
保持未初始化状态,即使您可以告诉你,当你的程序的整个逻辑被考虑时,这永远不会发生。
要解决这个问题,只需在声明 number
变量时分配一些虚拟默认值即可。
long number = -1L; // dummy default value to reassure the compiler.
Long.parseLong 可能会抛出异常,该异常将在您的 catch 块中捕获。在这种情况下,数字将不会被初始化,这就是您收到编译器错误的原因。
在声明数字时对其进行初始化,并确保其余代码能够处理将数字设置为该初始值的情况。
编译器试图说 number
不能保证被初始化。例如,如果以下语句抛出异常,则 number
将不会被初始化:
number = Long.parseLong(numStr);
然后您捕获异常,但 number
还没有 "touched",因此对该变量的所有进一步使用可能会导致意外行为甚至异常。
摆脱这种情况的通常方法是从一开始就为变量赋值:
long number = 0; // just an example, assign whatever value makes sense for you
更新
Java 规范可能会更清楚地说明这个主题,尤其是第 Initial Values of Variables and Definite Assignment
部分
因为编译器逻辑太重而无法检测
布尔条件,循环,不抛出捕获;
在 catch 子句中添加 "number=0;"
catch (NumberFormatException e) {
**number=0;**
System.out.print("That's not an integer. ");
}
我正在编写一个程序来计算用户定义整数中偶数、奇数和零的数量。奇怪的是,编译器根本不会编译。它说 "error: variable number might not have been initialized".
没有意义的是,据我所知,这个循环将保证 number
始终被初始化。我知道我可以通过在声明处初始化来轻松关闭编译器。我总是被告知,尽管在声明时初始化以帮助避免逻辑错误通常不是一个好主意。然而我最大的 scare/confusion 是我不知道为什么它不喜欢它。如果有异常,它会在 validInput = true
发生之前被捕获,不是吗?因此,当循环进行检查时,它将重新启动,因为 validInput
仍将是 false
。这甚至不是警告或任何东西;这是一个硬停止错误。我错过或没有看到什么?
我读过其他有关 if-checks 的案例,这与可能通过或可能不通过的检查不同。这个循环最终总是会通过,除非程序以某种方式提前退出(在这种情况下它无论如何都不会到达 for 循环)。如果这是重复的,有人可以指出我找不到的直接相关答案吗?谢谢!
public static void main( String[] args )
{
long number;
boolean validInput = false;
String numStr;
Scanner input = new Scanner(System.in);
do
{
System.out.print("Please enter an integer: ");
numStr = input.next();
try {
number = Long.parseLong(numStr);
validInput = true;
} catch (NumberFormatException e) {
System.out.print("That's not an integer. ");
}
} while (!validInput);
// Break each digit up by dividing by powers of 10.
int evens = 0, odds = 0, zeros = 0;
for (long temp = number; temp > 0; temp /= 10)
{
int digit = (int)(temp % 10);
if (digit == 0)
{
zeros++;
System.out.println(digit + " is a zero digit.");
}
else if (digit % 2 == 0)
{
evens++;
System.out.println(digit + " is an even digit.");
}
else
{
odds++;
System.out.println(digit + " is an odd digit.");
}
}
String evenStr = " even " + ((evens == 1) ? "digit" : "digits");
String oddStr = " odd " + ((odds == 1) ? "digit" : "digits");
String zeroStr = (zeros == 1) ? " zero" : " zeros";
System.out.println(number + " has " + evens + evenStr + ", " + odds + oddStr + ", and "
+ zeros + zeroStr + ".");
}
你是对的,number
永远不会因为你在 validInput
上的条件而逃脱你的未初始化循环。但是编译器不够聪明,无法弄清楚整个逻辑并确定它是安全的。它所看到的只是这一行位于 try-catch
块内,该块可能会或可能不会引发异常:
number = Long.parseLong(numStr);
...因此它看到 潜在 变量 number
保持未初始化状态,即使您可以告诉你,当你的程序的整个逻辑被考虑时,这永远不会发生。
要解决这个问题,只需在声明 number
变量时分配一些虚拟默认值即可。
long number = -1L; // dummy default value to reassure the compiler.
Long.parseLong 可能会抛出异常,该异常将在您的 catch 块中捕获。在这种情况下,数字将不会被初始化,这就是您收到编译器错误的原因。
在声明数字时对其进行初始化,并确保其余代码能够处理将数字设置为该初始值的情况。
编译器试图说 number
不能保证被初始化。例如,如果以下语句抛出异常,则 number
将不会被初始化:
number = Long.parseLong(numStr);
然后您捕获异常,但 number
还没有 "touched",因此对该变量的所有进一步使用可能会导致意外行为甚至异常。
摆脱这种情况的通常方法是从一开始就为变量赋值:
long number = 0; // just an example, assign whatever value makes sense for you
更新
Java 规范可能会更清楚地说明这个主题,尤其是第 Initial Values of Variables and Definite Assignment
部分因为编译器逻辑太重而无法检测 布尔条件,循环,不抛出捕获;
在 catch 子句中添加 "number=0;"
catch (NumberFormatException e) {
**number=0;**
System.out.print("That's not an integer. ");
}