In order for b (or any variable) to be a compile-time constant, it is
necessary but not
sufficient that it be final. Additionally, it must be a primitive type or
String, and
it must be initialized in the same line it is declared, using another compile-time constant expression. That last is the requirement that is not met here, as b was only set to 2 one line
after the declaration.
You may wonder why this is important, given that the variable b is definitely assigned using another compile-time constant (2) just one line after the declaration. The thing is, the compiler is not expected to analyze the code after a declaration to determine whether a variable is "really" a constant or not. It could be really simple code, or complex code; it doesn't matter.
In this case the code was really simple, and it may seem like the compiler "should have known" that b was a constant. But at the same time, since the code was so simple, the programmer could have simply initialized b on the same line it was declared:
If you want a variable to represent a compile-time constant, make sure it's initialized on the same line it's declared. If you can't do that, it's not a compile-time constant.