As I am preparing for OCPJP 21, came across Flow scoping topic.
i need some guidance understanding the concept. below is the code snippet
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");
}
}
above snippet results into "Cannot find symbol" for variable guppy. but if i remove the else keyword, like below. guppy variable remains in scope. no compiler error.
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);
}
my second observation as follows ref snippet
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);
}
}
above snippet successfully compiles but if I comment out return and instead add SOP statement, it results into cannot find symbol for data.
please guide me to understand the concept.
You can only use the variable if the compiler can proof that the code is only executed if the pattern matches.
Now, let's look at your example:
if(!(fish instanceof String guppy))
System.out.println("Eat!");
else if(!(fish instanceof String guppy)) {
throw new RuntimeException();
}
System.out.println(guppy);
Let's say fish
is not a String
. In this case, it would enter the if
statement printing Eat!
. Since it entered the if
, it doesn't enter the else if
so it would continue trying to print guppy
- But wait it is no String
so guppy
might not exist (it isn't definitely assigned).
If you skip the else
keyword, you are always throwing the exception if fish
isn't a String
. There, you only allow execution for String
s enduring that guppy
is valid.
Now, let's also check your second example:
if(!(number instanceof Integer data))
return;
//System.out.println("Eat!");
System.out.println(data.intValue());
Here, you can use data
because the compiler provably knows that number
is an Integer
. If it isn't, the execution flow would be cancelled/stopped by the return
statement (which can also be done using exceptions, break;
or continue;
).
If you remove the return
and replace it with a statement not impacting control flow, passing non-String
s could cause the System.out.println
to be executed.
That being said, please note that the Java compiler is not a powerful theorem-prover and doesn't try to be. It does some work to detect whether variables are assigned but it isn't complete (which would be impossible thanks to Gödel) i.e. there are cases where it's impossible that a statement is executed but the compiler doesn't know. The important thing the compiler focuses is soundness i.e. ensuring that it doesn't allow invalid code (and being predictable and following the specification).