Reputation: 1143
Before you say that this question has already been answered tons of times, here is my code snippet:
final int x;
try {
x = blah();
} catch (MyPanicException e) {
abandonEverythingAndDie();
}
System.out.println("x is " + x);
If invoking abandonEverythingAndDie()
has the effect of ending the execution of the whole program (say because it invokes System.exit(int)
), then x
is always initialized whenever it is used.
Is there a way in the current Java language to make the compiler happy about variable initialization, by informing it that abandonEverythingAndDie()
is a method which never returns control to the caller?
I do not want to
final
keyword x
while declaration, println
in the scope of the try...catch
block.Upvotes: 4
Views: 2423
Reputation: 54781
Logically, why would you want to do something with x
if blah()
had failed? x
would be uninitialized and this can be dangerous, and so Java prevents this. It's helping you in ways older languages like c would not. So move the println
inside would be the obvious solution.
try {
final int x = blah();
System.out.println("x is " + x);
} catch (MyPanicException e) {
abandonEverythingAndDie();
}
I think SRP could apply here, depending on your actual code, exception catching is arguably a responsibility, so I might split this one method into two. One that doesn't care about handling, and one that only handles.
public void doBlah throws MyPanicException {
final int x = blah();
System.out.println("x is " + x);
}
public void tryBlahOrDie {
try{
doBlah();
} catch (MyPanicException e) {
abandonEverythingAndDie();
}
}
Upvotes: 1
Reputation: 3146
Surely the simplest, and least hacky approach is just to use a temporary variable...
final int x;
int temp;
try {
temp = blah();
} catch (MyPanicException e) {
abandonEverythingAndDie();
}
x = temp;
System.out.println("x is " + x);
Simple.
Upvotes: 2
Reputation: 38424
Not without cheating a little by providing a little bit of extra information to the compiler:
final int x;
try {
x = blah();
} catch (MyPanicException e) {
abandonEverythingAndDie();
throw new AssertionError("impossible to reach this place"); // or return;
}
System.out.println("x is " + x);
You can also make abandonEverythingAndDie()
return something (only syntactically, it will of course never return), and call return abandonEverythingAndDie()
:
final int x;
try {
x = blah();
} catch (MyPanicException e) {
return abandonEverythingAndDie();
}
System.out.println("x is " + x);
and the method:
private static <T> T abandonEverythingAndDie() {
System.exit(1);
throw new AssertionError("impossible to reach this place");
}
or even
throw abandonEverythingAndDie();
with
private static AssertionError abandonEverythingAndDie() {
System.exit(1);
throw new AssertionError("impossible to reach this place");
}
Upvotes: 5
Reputation: 124225
I am not sure if that is an option but you can add
throw new RuntimeException()
or
return;
in your catch
final int x;
try {
x = blah();
} catch (MyPanicException e) {
abandonEverythingAndDie();
throw new RuntimeException(); // here
}
System.out.println("x is " + x);
Even if this added throw
will not be executed because of abandonEverythingAndDie
, compiler will know that flow of control from this catch
block can't go back to System.out.println("x is " + x);
so it will not require initialization of x
.
Upvotes: 1
Reputation: 72844
No, the compiler only checks that your code is legal. In this context, abandonEverythingAndDie
is treated as a blackbox and the compiler considers that not all branches cover the initialization of the variable. Even the below code is not accepted by the compiler:
final int x;
try {
x = blah();
} catch (MyPanicException e) {
abandonEverythingAndDie();
System.exit(-1); // the System.exit() itself is treated as a blackbox :)
}
System.out.println("x is " + x);
In other words, the compiler does not "think" about the possible dynamic execution in order to compile the program.
Upvotes: 4