45

In the below code:

final int a;
a=2;
byte b=a;   // error: possible loss of precision

Why do I get this error? Isn't a final variable compile time constant expression and hence implicitly narrowed to byte during the assignment?

In other words isn't the above code equivalent to:

final int a=2;
byte b=a;
haccks
  • 104,019
  • 25
  • 176
  • 264
paidedly
  • 1,413
  • 1
  • 13
  • 22

3 Answers3

51

From the JLS

A blank final is a final variable whose declaration lacks an initializer.

A constant variable is a final variable of primitive type or type String that is initialized with a constant expression (§15.28).

Your variable

final int a;

is a blank final variable. It lacks an initializer. The second paragraph doesn't apply to it because it is not initialized at declaration. It therefore isn't a constant expression.

This applies to fields as well.

Sotirios Delimanolis
  • 274,122
  • 60
  • 696
  • 724
43

The compiler isn't that smart.

We can tell that the value will always be 2. But what if we had something like this?

class ABC{
    final int a;

    public ABC(){
       if(Math.random() < .5){
          a = 2;
       }
       else{
          a = 12345;
       }

       byte b = a;
    }
}

The compiler is not smart enough to tell these two cases apart, so it gives you an error instead.

Kevin Workman
  • 41,537
  • 9
  • 68
  • 107
  • 31
    In fact the compiler isn't allowed to be that smart. – usr Jun 11 '15 at 21:24
  • @usr That's some serious primitive religion there. Seriously: Why is that? Compilers are sensitive to numbers `1`, `2`, `4`, and etc when multiplying. The case in this answer is clearly unsolvable, because the values returned from `random` depends on the time the program starts. – LyingOnTheSky Jun 12 '15 at 09:30
  • 9
    @LyingOnTheSky But even if the computation were deterministic and the compiler could figure it out, it still would not be allowed to treat it as a constant expression (removing the need for the cast). It's important that what is or isn't a valid java program doesn't depend on how smart a particular compiler is. – CodesInChaos Jun 12 '15 at 09:40
  • 1
    @CodesInChaos You are just saying that compilers should stick to the standard. Good point. – LyingOnTheSky Jun 12 '15 at 10:03
  • 3
    @LyingOnTheSky Pretty much. In C++ it's common for compilers to add their own extensions. In Java, it's basically forbidden (see the Microsoft lawsuit). – user253751 Jun 12 '15 at 10:49
2

As final variables can be delayed initialized and the compiler cannot determine for b that it has a value in the case branch.