为什么编译器会说如果变量需要在循环中才能通过,则可能不会对其进行初始化?

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. ");
}