Pietro Braione
Pietro Braione

Reputation: 1143

How do I avoid the "local variable may not have been initialized" Java compilation error? (yes, seriously!)

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

Upvotes: 4

Views: 2423

Answers (5)

weston
weston

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

Phil Anderson
Phil Anderson

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

Petr Janeček
Petr Janeček

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

Pshemo
Pshemo

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

M A
M A

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

Related Questions