为什么 x 没有在这里初始化?

Why is x not initialized in this?

为什么下面的x没有初始化?

public class rough {
    public static void main(String[] args) {
        int x;
        boolean found = false;
        for (int i = 0; i < 10; i++) {
            if (Math.random() < 0.5) {
                found = true;
                x = 10;
                break;
            }

        }
        if (!found)
            x = -1;
        System.out.println(x);//x isn't initialized here
    }
}

平均而言,对于一半的迭代,for 循环内的 if 将是 true,因此初始化 x。对于另一半,found 保持 false 因此外部 if 将初始化。因此,我不明白为什么编译器会生气。

作为最终的蒸馏(见下面的连续简化),考虑

public static void main(String[] args) {
        int x;
        boolean found = false;
        if (!found)
            x = -1;

        System.out.println(x);
    }

这也给出了 x 不是 init 的错误。

之前的简化

更令人惊讶的是,改变 if (Math.random() < 0.5)if(true)也有同样的问题

事实上,进一步调查,将原来的for循环替换为这些

        for (int i=0;i<1;i++)
           x = 10;
 for (; !found; ) {
            x = 10;
            break;
        }

同样更糟。只有 for(;;){... break;} & for(;true;){... break;} 不引发任何初始化。错误。

编译器无法轻松检测到所有导致 x 被初始化的分支,但是您可以通过将 -1 分配给 x 来很容易地修复它(和代码)首先。像

public static void main(String[] args) {
    int x = -1;
    for (int i = 0; i < 10; i++) {
        if (Math.random() < 0.5) {
            x = 10;
            break;
        }
    }
    System.out.println(x);
}

现在你不需要 found(所以我也删除了它)。

(将其写成一个单独的答案,因为我认为从评论中删除它会受益)。

这是语言律师的回答。

变量使用前的语言规范requires initialization

规则包括:

  1. 必须在代码的所有可能路径上为变量赋值。规范将其称为 'definite assignment'.

  2. 编译器在此分析中不考虑表达式的值。请参见示例 16.2。

第二条规则解释了为什么即使在对我们来说 'obvious' 的情况下,编译器也无法使用该知识。即使编译器编写者愿意做更深入的分析,遵守 Java 规范也不允许这样做。

如果下一个问题是 'but why?' 那么我不得不猜测,但标准的重点是获得一致的行为。您不希望一个编译器接受另一个编译器拒绝的东西是合法的 Java。