0

Why does not initializing a local final variable compile? This behavior seems to contrast final fields where not initializing a gives a compilation error.

class Test {

    final Test test1; // doesn't compile

    public Test(){
        final Test test2; // does compile
    }
}

What's the logic behind this choice?

flakes
  • 21,558
  • 8
  • 41
  • 88
  • I don't know why I'm getting down voted. I'm just asking the reasoning behind the language rules :s – flakes Feb 12 '16 at 14:55

1 Answers1

2

This comes from the rules of the JLS.

From 4.12.4

It is a compile-time error if a final variable is assigned to unless it is definitely unassigned (§16) immediately prior to the assignment.

From 4.12.5

A local variable (§14.4, §14.14) must be explicitly given a value before it is used, by either initialization (§14.4) or assignment (§15.26), in a way that can be verified using the rules for definite assignment (§16).

From 8.3.1.2

A blank final instance variable must be definitely assigned (§16.9) at the end of every constructor (§8.8) of the class in which it is declared; otherwise a compile-time error occurs.

So the technical reason why that works is because it's not forbidden. Fields must be initialized by the time the object is constructed. Local variables only need to be initialized before they're used.

The logic behind it is that a class variable might be referenced from another object, so it needs to be initialized by the time that another object might have an initialized reference to it. A local variable doesn't escape it's scope though, so the compiler can guarantee that it's not referenced as long as it's not used within that scope.

resueman
  • 10,572
  • 10
  • 31
  • 45
  • So it's primarily because checking the local usage is easier? I'm a little curious why you can't do something like this then: `final Test test2; Runnable test3 = () -> { test2=new Test() }; test3.run();` Wouldn't this still maintain scope with the local? – flakes Feb 12 '16 at 14:52
  • 1
    @flkes Doing that is going to violate the rules of not reassigning to a `final` variable. There's nothing to stop you from doing `test3.run(); test3.run();`, or passing the `Runnable` out of the method. Technically you can prove that it doesn't do that, but the rules and logic would get very complicated for no real gain. And I wouldn't really say that it's because checking the local usage is easier; it's because it's possible at all. When it's a field, the compiler *can't* know how it will be used. With a local variable, it can know, and can guarantee safety. – resueman Feb 12 '16 at 14:57
  • Just for symmetry, it seems like it would be better if not initializing a local var was forbidden as well. I guess it would probably break old code, but apart from that, is there a reason why it should actually be allowed? – flakes Feb 12 '16 at 15:13
  • @flkes I can't think of any reason to allow it, other than just that it doesn't cause any problems. A decent IDE will warn about it, so it's not likely to be an issue. – resueman Feb 12 '16 at 15:15
  • 1
    @user That's a different case than what I'm describing though! – flakes Feb 12 '16 at 15:51