JavaConstants (final)

Constants (final)

Sometimes a value should never change once it's set — the number of days in a week, a mathematical constant, a maximum allowed retry count. Java lets you express this intent directly in code with the final keyword.
The final Keyword
Applying final to a variable declaration means that variable can be assigned a value exactly once. After that initial assignment, any attempt to reassign it is a compile-time error. This turns an ordinary variable into a constant.

A final variable

Java
public class FinalDemo {
    public static void main(String[] args) {
        final int MAX_ATTEMPTS = 3;

        System.out.println(MAX_ATTEMPTS);

        // MAX_ATTEMPTS = 5; // compile-time error!
    }
}
3
Warning
Uncommenting the second assignment produces: compile-time error cannot assign a value to final variable MAX_ATTEMPTS. Once a final variable is initialized, the compiler locks it — there is no way around this at runtime.
Naming Convention: ALL_CAPS_WITH_UNDERSCORES

By strong convention, Java constants are named entirely in uppercase letters, with words separated by underscores. This makes constants instantly recognizable wherever they appear in code, distinguishing them from regular variables and methods (which use camelCase).

  • Good: MAX_ATTEMPTS, DEFAULT_TIMEOUT, PI, TAX_RATE

  • Not idiomatic: maxAttempts, defaultTimeout (fine for regular variables, but not the convention for constants)

static final: The Idiomatic Class-Level Constant
Combining static with final is the standard way to define a constant that belongs to the class itself rather than to any one object, and is shared identically by every instance. This is by far the most common way constants are declared in real Java code.

A class-level constant

Java
public class Circle {
    static final double PI = 3.14159;

    double radius;

    Circle(double radius) {
        this.radius = radius;
    }

    double area() {
        return PI * radius * radius;
    }

    public static void main(String[] args) {
        Circle c1 = new Circle(2.0);
        Circle c2 = new Circle(5.0);

        System.out.println("Area 1: " + c1.area());
        System.out.println("Area 2: " + c2.area());
        System.out.println("Shared constant: " + Circle.PI);
    }
}
Area 1: 12.56636
Area 2: 78.53975
Shared constant: 3.14159
Note
Because PI is static, only one copy of it exists in memory, shared by every Circle object. Because it is also final, no code — anywhere in the program — can ever change its value after class loading. Together they express exactly what a constant should be: one shared, unchangeable value.
Tip
Access a static final constant through the class name (Circle.PI) rather than through an instance. This makes it clear at the call site that you're reading a shared constant, not an object's own field.
final Prevents Reassignment — Not Mutation
This is the single most misunderstood aspect of final. When applied to a reference-type variable, final only guarantees that the variable itself cannot be pointed at a different object. It says nothing about the object that reference points to — if that object is mutable, its internal state can still be freely changed.

A final list is not an immutable list

Java
import java.util.ArrayList;
import java.util.List;

public class FinalListDemo {
    public static void main(String[] args) {
        final List<String> names = new ArrayList<>();

        names.add("Alice");
        names.add("Bob");
        names.remove("Alice");

        System.out.println(names); // [Bob] — the object WAS mutated

        // names = new ArrayList<>(); // compile-time error!
        // Reassigning the reference itself is what's forbidden.
    }
}
[Bob]
Warning
The names variable is final, yet we just added and removed elements from the list it points to — and that compiled and ran without any complaint. final only locks the variable's reference (it must always point to that one specific ArrayList object); it does not freeze the object's contents. If you need true immutability, you must use an immutable collection (such as List.copyOf(...) or Collections.unmodifiableList(...)) or an immutable class design — final alone does not provide it.
final on Method Parameters and Fields
final is not limited to local variables. It can also be applied to method parameters (preventing the parameter from being reassigned inside the method body) and to instance fields (in which case the field must be assigned exactly once, typically in the constructor).

final on a field, assigned in the constructor

Java
public class User {
    final String username; // must be set exactly once

    User(String username) {
        this.username = username; // allowed: first assignment
    }

    public static void main(String[] args) {
        User u = new User("admin");
        System.out.println(u.username);
    }
}
admin

Applied To

What final Guarantees

Local variable

Can only be assigned once

static final field

One shared value across the whole class, set once

Instance field

Must be assigned exactly once (often in the constructor)

Reference-type variable

The reference can't change — the object it points to still can

Tip
Reach for static final whenever you have a value that is fixed for the lifetime of the program — configuration values, mathematical constants, fixed limits. It communicates intent to every future reader of the code and lets the compiler catch accidental reassignment for you.