-1

I know that:

  • A blank final class variable must be definitely assigned by a static initializer of the class in which it is declared, or a compile-time error occurs.

  • A blank final instance variable must be definitely assigned at the end of every constructor of the class in which it is declared, or a compile-time error occurs.

Why final variable cannot be assigned just once at any time instead of just at declare time?

Yarl
  • 728
  • 1
  • 7
  • 26
  • Because it wouldn't have a value otherwise. – Elliott Frisch Apr 09 '16 at 20:41
  • I don't understand your confusion. This is a language feature. That's how it was decided. – Savior Apr 09 '16 at 20:41
  • @Elliott Frisch: You are saying that final vars does not have initial values? – Yarl Apr 09 '16 at 21:01
  • @Uzivatel828 No. I'm saying they **must**! Consider `static final String b;` and `final String a;`, something must initialize `a` and `b`. – Elliott Frisch Apr 09 '16 at 21:09
  • @Elliott Frisch: I have meant these initial values – https://docs.oracle.com/javase/specs/jls/se8/html/jls-4.html#jls-4.12.5. So my question lasts. – Yarl Apr 09 '16 at 21:17
  • The *language* requires you to be explicit when defining a `final` variable, this allows the compiler to perform [**constant propagation**](https://en.wikipedia.org/wiki/Constant_folding#Constant_propagation). At runtime, there *may not be* a `final` variable because the value is inserted in the variable's place (whenever possible). – Elliott Frisch Apr 09 '16 at 21:19
  • @Elliott Frisch: So constant propagation is demanding that the final variable must by initialized by the programmer. That in fact means final variable is never initialized by the compiler so it cannot be used as not initialized by the programmer. Is it okay? – Yarl Apr 10 '16 at 06:16

3 Answers3

2

The corollary to this, for non-final variables, is the initial value of a variable. Every field receives an initial value depending on its type - usually a variant of 0 or null.

It's implied here that, if you're declaring a variable to be final, then you have a specific value in mind that you wish that variable to be assigned and not have changed later in its run. Java doesn't know what value that is, and it likely takes away the convenience of automatically declaring those values for you so to not interfere with the developer's intentions.

That and requiring that all final variables be initialized is to support all variables being definitely assigned before their use. You can use a non-final field that you don't initialize to some value - it'll likely be null though - but you can't use a local variable that you haven't initialized yet for the same reason.

Makoto
  • 104,088
  • 27
  • 192
  • 230
  • Are sure that only reason for this is intending final variables to be forcibly used only with other value than the initial value? – Yarl Apr 09 '16 at 21:00
  • @Uzivatel828: Using the `final` keyword is a developer-conscious decision in that you do *not* want that value to change under any circumstances. There's the concept of [effectively final](http://stackoverflow.com/q/20938095/1079354), in which Java 8 and above can imply that a variable is effectively final if it's never reassigned again, but that has weaker implications in that its usage isn't *guaranteed* final. The developer is making the decision as to whether or not the value is going to be changed after it's declared. – Makoto Apr 09 '16 at 21:38
  • I think this answer hits pretty close. A `final` element is effectively a constant value in Java. It has exactly one value. For this guarantee to hold, a `final` element: (1) must be assigned exactly once on every code path; and (2) cannot have a value prior to initialization. – Mike Strobel Jun 30 '16 at 09:56
1

First it is not something against null. The following is legal too:

final String ABC;
{
    ABC = null;
}
static final String DEF;
static {
    DEF = null:
}
final String GHI = null;

It was the following decision:

When a final field or a local variable is not initialized it can very well be a bug, forgetting to initialize. (For normal fields it would be too much boiler code, and zeroing of fields is provided.)

For local variables you might find this obvious. As final variables can only be assigned once, and it was decided that this should happen only during construction (otherwise you would need administration of whether the variable was initialized).

Joop Eggen
  • 107,315
  • 7
  • 83
  • 138
1

Language design decisions are always a trade off between flexibility and error prevention. In this case, there are some simple questions to check:

In case, there is a code path in which a final variable is not assigned:

  • How likely is it that the developer declares a final variable just to hold the default value, null, 0 or false?
  • In contrast, how likely is it that the developer has forgotten the initialization or overlooked a possible code path, in other words, rejecting this code prevents a nasty bug?
  • How much work is it for the developer, to write the explicit assignment, if (s)he really wants the default value?

I think, trying to answer these questions should lead to the rationale behind this design decision.

This is the place for an important clarification. In case of local variables, all variables must be initialized before use. The restriction is only lifted for non-final heap variables, read, fields and array elements.

In case of arrays, it should be obvious why developers are not enforced to write explicit default values when arrays can be instantiated for lengths up to 2³¹ elements. For non-final instance fields, this decision can be discussed. But such a discussion would be outside the scope of Stackoverflow…

Holger
  • 285,553
  • 42
  • 434
  • 765
  • Java unfortunately has no form of `final` array (such things would be useful if there were a constructor that took a `T[][]` and a two `int[]` of the same size, and populated the new array with copied ranges of from the indicated source arrays). As for non-`final` instance variables, it's common for those to get filled in at some time after the constructor completes. The requirement to write `final` variables stems from the fact that if they're not written in the constructor they won't get written at all. – supercat Jul 11 '16 at 20:45
  • 1
    @supercat: even if there was some kind of constructor for arrays, I can’t imagine a useful logic for ensuring that every element is written exactly once, like with final variables. Even expanding the flow analysis to recognize loops over the entire array is tough, but for non-trivial initialization of large arrays I don’t see a solution. For fields, sometimes, you have to use non-final local variables which you write to the final fields at the constructor’s end to make the compiler happy, but that doesn’t scale to array initialization… – Holger Jul 12 '16 at 07:58
  • One approach would be to say that the constructor must specify a list of array ranges which would be concatenated to yield the destination array. It would also be possible to allow for sparse construction, or have an `ImmutableArrayBuilder` which would be somewhat analogous to a `StringBuilder` (manipulate via mutable interface, and then yield a new `ImmutableIntArray` object. If immutable array types and mutable array types were subtypes of a common "readable" array type, a lot of functions could accept the latter and work with either of the former. – supercat Jul 12 '16 at 14:03