Java 为什么编译器说如果变量是';在一个循环中,它需要什么才能通过?
我正在写一个程序,计算用户定义整数中的偶数、赔率和零数。奇怪的是,编译器根本不会编译。它说“错误:变量号可能尚未初始化” 不合理的是,据我所知,这个循环将保证Java 为什么编译器说如果变量是';在一个循环中,它需要什么才能通过?,java,while-loop,compiler-errors,initialization,Java,While Loop,Compiler Errors,Initialization,我正在写一个程序,计算用户定义整数中的偶数、赔率和零数。奇怪的是,编译器根本不会编译。它说“错误:变量号可能尚未初始化” 不合理的是,据我所知,这个循环将保证number始终被初始化。我知道我可以通过在声明处初始化来轻松关闭编译器。我一直被告知,虽然在声明时初始化以帮助避免逻辑错误通常不是一个好主意。然而,我最大的恐惧/困惑是,我不知道为什么它不喜欢它。如果出现异常,它将在validInput=true发生之前被捕获,不是吗?因此,当循环到达检查时,它将重新启动,因为validInput仍然是f
number
始终被初始化。我知道我可以通过在声明处初始化来轻松关闭编译器。我一直被告知,虽然在声明时初始化以帮助避免逻辑错误通常不是一个好主意。然而,我最大的恐惧/困惑是,我不知道为什么它不喜欢它。如果出现异常,它将在validInput=true
发生之前被捕获,不是吗?因此,当循环到达检查时,它将重新启动,因为validInput
仍然是false
。这甚至不是一个警告或任何东西;这是一个很难阻止的错误。我错过了什么或没有看到什么
我读过关于if检查的其他案例,这与检查中可能通过或不通过的情况不同。除非程序以某种方式提前退出(在这种情况下,它无论如何都不会到达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
变量时指定一些伪默认值
long number = -1L; // dummy default value to reassure the compiler.
parseLong可能会抛出一个异常,该异常将被捕获到catch块中。在这种情况下,数字将不会被初始化,这就是为什么会出现编译器错误
声明数字时初始化数字,并确保代码的其余部分能够处理数字设置为该初始值的情况。编译器试图说,
number
不保证初始化。例如,如果以下语句引发异常,number
将不会初始化:
number = Long.parseLong(numStr);
然后捕获异常,但是没有“触碰”到number
,因此进一步使用该变量可能会导致意外行为甚至异常
通常的方法是从一开始就分配变量值:
long number = 0; // just an example, assign whatever value makes sense for you
更新
Java规范可能会在这个主题上提供更多信息,尤其是章节和,因为编译器的逻辑太重,无法检测 布尔条件,循环,不抛出捕获 在catch子句中添加“number=0;”
catch (NumberFormatException e) {
**number=0;**
System.out.print("That's not an integer. ");
}
如果异常被捕获,它是否会继续,然后到达
while(!validInput)
,由于捕获将跳过validInput=true
,因此将继续执行,直到提供validInput(因此无异常输入)并将其分配给number
?如果编译器允许您编译和执行代码,然而,标准编译器的行为是抛出一个错误——它不能对代码进行太深的分析而“发现”这一点。你知道,编译器不可能检查所有可能的变量和变量值组合、程序流等——抛出一个错误并使程序员“修复”更容易代码…我现在明白它不起作用了,因为它“太难”了。但我还是不明白为什么。编译器在编译时已经在跟踪程序(不是吗?),因此它必须提前查看是否在该点初始化,不是吗?我不明白为什么它需要像你说的那样检查每一个变化,甚至任何变化。追根究底,为什么它不能看到跳出循环的唯一方法是首先初始化数字?在谷歌搜索了一些关于这个主题的详细信息后,我直接在Java规范中找到了,也许这会对这个问题有所帮助:好的,谢谢。编译器一直在发挥巨大的魔力,我只是认为这对它来说很容易。在初始化之后,有没有什么方法可以让编译器或其他人帮助我处理我前面提到的潜在逻辑错误?不过,这并没有遵循我的问题或程序的逻辑。是的,它将抛出一个不初始化它的异常,但要突破while
循环到达for
循环,唯一的方法是如果validInput
为true。只有在number
初始化后才能发生异常。否则,它将按照程序继续循环,直到发生这种情况。