为什么编译器说如果变量需要在循环中传递,变量可能未被初始化?
我正在编写一个程序,用于统计用户定义的整数中的平均数,可能性和零的数量。奇怪的是,编译器根本不会编译。它说“错误:可能的数字可能没有被初始化”。为什么编译器说如果变量需要在循环中传递,变量可能未被初始化?
什么是没有意义的,据我所知,这个循环将保证number
总是初始化。我知道我可以通过在声明中初始化来轻松关闭编译器。我总是被告知,尽管在声明中初始化以避免逻辑错误通常是一个糟糕的主意。然而,我最大的恐惧/困惑是我不知道为什么它不喜欢它。如果有例外,它会在validInput = true
曾经发生之前被捕获,不是吗?那么当循环进行检查时,它会重新启动,因为validInput
仍然是false
。这甚至不是一个警告或任何东西;这是一个硬性的错误。我错过了什么或没有看到?
我已阅读其他关于if-checks的案例,这与在可能通过或不通过的支票中的位置不同。这个循环总是会最终通过,除非程序以某种方式退出(在这种情况下,它不会到达for-loop)。如果这是重复的,有人能指出我找不到直接相关的答案吗?谢谢!
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
不保证被初始化。例如,如果下面的语句抛出一个异常,number
不会被初始化:
number = Long.parseLong(numStr);
然后,您可以捕获该异常,但number
还没有“感动”,让变量的所有进一步的用途可能潜在导致意外的行为甚至例外。
摆脱这种通常的方法是从一开始就指定变量值:
long number = 0; // just an example, assign whatever value makes sense for you
UPDATE
Java规范可以摆脱一些关于这个论题更多的光线,尤其是部分Initial Values of Variables和Definite Assignment
你说得对,number
将永远无法逃脱的因为validInput
你的病情的环路初始化。但编译器不够聪明,无法确定整个逻辑并确定它是安全的。所有它看到的是,这条线是try-catch
块可能会或可能不会引发异常内:
number = Long.parseLong(numStr);
...等它看到潜力为number
变量保持未初始化,甚至尽管你可以说当你的程序的整个逻辑被考虑时,这绝不会发生。
若要解决声明number
变量时只指定一些虚拟默认值。
long number = -1L; // dummy default value to reassure the compiler.
好的,谢谢。编译器在我一直认为对它来说很容易的情况下工作的非常神奇。有什么方法可以继续获得编译器或者帮助解决潜在的逻辑错误,就像我之前在初始化之后提到的那样? – BrainFRZ
Long.parseLong可能会抛出一个异常,它将被捕获到您的catch块中。在这种情况下,编号不会被初始化,这就是为什么你得到编译器错误。
声明它时初始化数字,并确保代码的其余部分能够处理数字设置为初始值的情况。
虽然这不是我的问题或程序的逻辑。是的,它会抛出一个不初始化它的异常,但是如果'validInput'为true,那么抛出'while'循环来达到'for'循环的唯一方法就是。这只能在'number'被初始化为无异常之后才会发生。否则,在程序之后,它会持续循环直到发生这种情况。 – BrainFRZ
对于编译器来说太重逻辑来检测 布尔条件,循环,不抛出catch;
add“number = 0;”赶上子句
catch (NumberFormatException e) {
**number=0;**
System.out.print("That's not an integer. ");
}
如果异常被抓到,是不是会继续,那么到达'while(!validInput);',这仍然是true,因为catchIn会跳过'validInput = true',因此重复直到validInput(和因此无异常输入)被提供并分配给'number'? – BrainFRZ
如果编译器允许您编译和执行代码,则会出现这种情况,但标准编译器的行为会引发错误 - 它无法分析代码太深以至于无法“发现”此代码。 –
你知道,编译器不可能检查变量值,程序流等的所有可能的变体和组合。 - 更容易抛出错误并使程序员“修复”代码... –