Skip to content

final fields and "might not have been initialized"

โ˜• Java 17 ยท Giving Variables Their First Value ยท 2/3

Fields get default values, locals don't. final adds one more rule on top.

final locals

A final local variable follows the local rule (assign before use), and can be assigned only once:

public void launch() {
    final String platformName = "NetStream";
    platformName = "Other";        // โŒ doesn't compile
    System.out.println(platformName);
}

final fields get no default

A final field is not auto-initialized. You must assign it exactly once, in one of three places:

  1. on its declaration,
  2. in an instance initializer block,
  3. in every constructor.
public class StreamingPlatform {
    final int maxStreams;

    public StreamingPlatform(int max) {
        this.maxStreams = max;     // โœ… assigned in the constructor
    }
}

Forget all three and the class doesn't compile. The compiler reports it on the field itself:

public class Subscription {
    final int maxScreens;          // โŒ not initialized in the default constructor
}

Once assigned, the field can never change: a reliable value for the object's whole life.

Every path must assign it

The compiler checks that a local variable is assigned on every possible path before it's read. This is called definite assignment:

public void show(boolean premium) {
    int views;
    if (premium) {
        views = 5;
    }
    System.out.println(views);     // โŒ might not have been initialized
}

When premium is false, views has no value. Assign it on every branch, or give it a starting value:

int views;
if (premium) {
    views = 5;
} else {
    views = 0;
}
System.out.println(views);         // โœ… assigned on both paths

The compiler doesn't run your code: it only looks at the possible paths. If one path could skip the assignment, it refuses.

Time to see the defaults with your own eyes.

๐Ÿ’ป Code: Java17_Part_1_Fundamentals_Core_Syntax on GitHub

โ† Three kinds of variables ยท Next: the lab โ†’