krishnaz
krishnaz

Reputation: 649

Java "blank final field may not have been initialized" Exception thrown in method oddness

I have some code like:

final int var1;    

if ( isSomethingTrue ) {

   var1 = 123;

} else {
   throwErrorMethod();
}

int var2 = var1;

And throwErrorMethod is defined something like:

private void throwErrorMethod() throws Exception{

   throw new Exception();

}

And I get a blank final field may not have been initialized compile error for the var2 = var1 statement. If I inline the method, compilation is fine!

  1. Doesn't the compiler see the throws Exception on the method called?
  2. How come an error which has the word may in it stops compilation?!?

Upvotes: 14

Views: 22998

Answers (5)

Howard
Howard

Reputation: 39207

A method declared "throws Exception" does not have to throw this exception in any run path. Therefore the compiler does not know whether always an exception will be thrown by the method and assumes an normal termination also. Thus it might be that var1 is not initialized.

Upvotes: 0

Peter Lawrey
Peter Lawrey

Reputation: 533670

Exceptions are supposed to be exceptional. It doesn't assume that an exception is always thrown.

The compiler uses the word may as it cannot tell if you could access an uninitialsied variable. Additionally, you may change which the method does without recompiling this class and any assumption it made would be incorrect.

If you want to throw an Exception always, you can do

final int var1;    

if ( isSomethingTrue ) {

   var1 = 123;

} else {
   throw exceptionMethod();
}

int var2 = var1;

// later
public Exception exceptionMethod() {
    return new Exception("Complex-Exception-String");
}

Upvotes: 7

Ted Hopp
Ted Hopp

Reputation: 234847

If you want to tell the compiler that an error will definitely be thrown, but don't want to in-line the logic for constructing the error, you can do something like this:

} else {
   throw createErrorMethod();
}

where createErrorMethod() is declared to return some kind of Throwable.

Upvotes: 1

Jon Skeet
Jon Skeet

Reputation: 1502106

  1. No, the compiler doesn't determine that the throwErrorMethod will never complete normally. There's nothing in the specification to suggest it should. Unfortunately there's no way to indicate that a method will never return normally.

  2. It's only "may" because there's a potential execution path which doesn't initialize the variable. The presence of such an execution path is defined to be an error.

You may find this pair of blog posts (part 1; part 2) by Eric Lippert interesting. It's about C# rather than Java, but it's the same principle.

Upvotes: 19

Kirk Woll
Kirk Woll

Reputation: 77576

The compiler doesn't do the sort of check you are expecting. It does not determine for sure that throwErrorMethod actually throws an exception every time. Therefore, it assumes that it's possible to go into your else clause, invoke throwErrorMethod, return from that method, and then not initialize var1 (which must be initialized).

Upvotes: 1

Related Questions