当我准备 OCPJP 21 时,遇到了 Flow 范围主题。
我需要一些指导来理解这个概念。下面是代码片段
public class Question28
{
static void getFish(Object fish) {
if(!(fish instanceof String guppy))
System.out.println("Eat!");
else if(!(fish instanceof String guppy)) {
throw new RuntimeException();
}
System.out.println(guppy);
System.out.println("Swim!");
}
public static void main(String args[]) {
getFish("ashish");
}
}
上述代码片段导致变量 guppy “无法找到符号”。但如果我删除 else 关键字,如下所示。guppy 变量仍然在范围内。没有编译器错误。
static void getFish(Object fish) {
if(!(fish instanceof String guppy))
System.out.println("Eat!");
if(!(fish instanceof String guppy)) {
throw new RuntimeException();
}
System.out.println(guppy);
我的第二个观察如下参考片段
class Sample2 {
static void printNumberTwice(Number number) {
if(!(number instanceof Integer data))
return ;
//System.out.println("Eat!");
System.out.println(data.intValue());
}
public static void main(String args[]) {
printNumberTwice(5);
}
}
上述代码片段成功编译,但如果我注释掉返回并添加 SOP 语句,则会导致无法找到数据符号。
请指导我理解这个概念。
只有当编译器可以证明只有模式匹配时才会执行代码时,您才能使用该变量。
现在,让我们看一下您的示例:
假设
fish
不是String
。在这种情况下,它将进入if
语句打印Eat!
。由于它进入了if
,所以它不会进入,else if
所以它将继续尝试打印guppy
- 但等一下,它不是,String
所以guppy
可能不存在(它没有明确分配)。如果你跳过
else
关键字,你总是会抛出异常 iffish
isn't aString
。在那里,你只允许执行有效的String
持久性guppy
。现在,让我们检查一下你的第二个例子:
这里,你可以使用
data
因为编译器可以证明这number
是一个Integer
。如果不是,执行流程将被return
语句取消/停止(也可以使用异常break;
或 来完成continue;
)。如果删除
return
并将其替换为不影响控制流的语句,则传递非String
s 可能会导致System.out.println
执行。话虽如此,请注意 Java 编译器并不是一个强大的定理证明器,也不会试图成为它。它会做一些工作来检测变量是否被赋值,但它并不完整(这在哥德尔看来是不可能的),即有些情况下语句不可能被执行,但编译器却不知道。编译器关注的重要事情是健全性,即确保它不允许无效代码(并且是可预测的并遵循规范)。