Java:错误:变量可能未被初始化

6

我正在学习Java,但是遇到了一个错误。我知道这个问题已经被问过很多次,但是没有一个答案似乎能够回答我的问题。代码的主体如下:

String[] number = {"too small", "one", "two", "three", "four", "too large"};
int i;
if(num<1){
    i=0;
}
if(num==1){
    i=1;
}
if(num==2){
    i=2;
}
if(num==3){
    i=3;
}
if(num==4){
    i=4;
}
if(num>4){
    i=5;
}
return number[i];

在变量“num”被声明、初始化和赋值之前。我得到的错误是:“变量'i'可能未被初始化”,并指向最后一行(return number[i];)。
问题在于,如果我声明'i'并立即赋一个值(int i=0;),代码就能正常运行。但如果我不给'i'赋值,即使每个“if”后都有可能的值被赋予,我仍会得到错误提示。
例如,在C语言中,我不会遇到这种错误。
谢谢。

编译器告诉你它想让你赋值;显然,当你这样做时它会工作。为什么你不想这样做呢? - Jeroen Vannevel
1
rgettman解释得很好。 我的首选修复方法是(1)在所有分支上使用else,并且(2)使最后一个分支成为没有另一个ifelse,即else { ...而不是else if (num> 4) {...。 我认为这对读者更清晰,同时避免了“明确赋值”问题。 在这种特殊情况下,我只会写int i =(num <1)?0:(num> 4)?5:num; - ajb
1
@ajb 这里三元条件运算符似乎太复杂了。我会用 else :| - user2864740
@JeroenVannevel 它确实能工作,但我想知道为什么其他方法不行。 - user3728000
这个 jls 章节定义了明确赋值的规则。 - Alex - GlassEditor.com
@user3728000 在C语言中,你只会得到未定义的行为;-) 尽管有些编译器会有类似的警告可以启用。 - user2864740
2个回答

12

Java不会分析你的if块逻辑以确定其中一个if语句将被执行并给i赋值。它很简单,也看到了if语句都有可能不执行。在这种情况下,在使用i之前没有任何值会被赋给它。

即使Java会为类变量和实例变量提供默认值,但不会为局部变量提供默认值。JLS的第4.12.5节对此进行了说明:

程序中的每个变量在使用它之前必须具有值:

局部变量(§14.4、§14.14)在使用之前必须显式地通过初始化(§14.4)或赋值(§15.26)来赋值。

在声明i时,赋予一些默认值以满足编译器。

int i = 0;
// Your if statements are here.
return number[i];

1
在大多数情况下,我不建议使用默认赋值,因为我发现它可能会隐藏问题 - 即忘记处理某些逻辑。相反,我通常会在更明确和清晰的意图处使用适当的 else(例如,正确的解决方案也可以是早期返回或抛出异常)。 - user2864740
1
@user2864740 在这种情况下我同意你的看法。然而,我遇到过一些循环的情况,在这些情况下我可以确定一个变量在循环退出之前总是会被赋值,但是没有好的方法来重新排列代码以使编译器相信这一点。我确实看到你说了“大多数情况”。 - ajb
1
@rgettman 奇怪的是,当我在2-4使用'else if(...)',在5使用'else{...}',而不在开头初始化变量'i'时,代码却能够正常工作。就好像Java并不假设所有可能性都包含在多个'if'中,而是理解所有可能性都包含在一个'if'和多个'else'中。 - user3728000
@user3728000,这没什么奇怪的。当你像这样使用else时,编译器可以轻松地判断(而无需分析实际的if条件)其中一个分支必须被执行,因此i将在某个地方被赋值。 - ajb
@user2864740 你说得对!那很有道理:要么满足'if'里的条件,要么满足'else'里的条件,没有其他选项!非常感谢大家。 - user3728000
显示剩余3条评论

0

如果你想清理代码,你可以非常轻松地做到这一点:

String[] number = {"too small", "one", "two", "three", "four", "too large"};
int i = num;
if (i < 1) { i = 0; }
if (i > 4) { i = 5; }
return number[i];

或者如果num的值并不重要:

String[] number = {"too small", "one", "two", "three", "four", "too large"};
if (num < 1) { num = 0; }
if (num > 4) { num = 5; }
return number[num];

即使你之前的代码在逻辑上看起来没问题,编译器并不总能与人类智慧相媲美。给它一个默认值将有助于满足方法的安全性要求。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接