Constants (final)
In short: A variable whose value can’t be changed after assignment — marked with the final keyword in Java.
In more detail: Constants make code safer and more readable: the compiler prevents accidental overwriting, and a meaningful name (e.g. MAX_RETRIES) replaces “magic numbers” in the code. Convention in many languages: write constants entirely in uppercase with underscores (SCREAMING_SNAKE_CASE).
In Depth
Basic usage
final int MAX_RETRIES = 3;
final String API_URL = "https://api.example.com";
// final also applies to method parameters and classes
final class Configuration { } // can no longer be inherited from
void process(final int value) {
// "value" can no longer be changed within the method
}Shallow vs. deep immutability
Important: final on an object (rather than a primitive value like int) only prevents the variable from pointing to a different object (“reference immutability”) — the content of the object itself can still remain changeable, if its class allows that. A final List<String>, for example, can still have elements added (list.add("new") works), only the variable itself can no longer be reassigned to point to a completely different list (list = newList would be a compile error). For real, deep immutability (where the object’s content can also never be changed again), you additionally need an object that’s immutable from the ground up — e.g. List.of(...) instead of a normal ArrayList, or a record with only final fields.
final at the class and method level
Besides variables, final can also be applied to classes (which can then no longer be inherited from/extended — String in Java is itself final, for security and performance reasons) and methods (which can then no longer be overridden in subclasses). This is a deliberate design tool: a final class signals “this implementation is complete, no extension is intended”, which prevents misuse and unexpected behaviour from subclasses.
Naming convention and benefit
Constants are often used for configuration values, mathematical constants, or error codes that should never change at runtime. Convention in many languages: write constants entirely in uppercase with underscores (SCREAMING_SNAKE_CASE, e.g. MAX_RETRIES), to visually distinguish them immediately from normal, mutable variables — you can tell from the name alone that this value never changes. The big practical benefit is that a mistake (accidentally changing a value that should actually stay constant) is caught at compile time, instead of only showing up as a hard-to-trace bug at runtime — a classic example of “fail fast”: better to fail early and clearly than late and mysteriously.
final as a safety mechanism for multithreading
In concurrent code (several threads at once), final fields are especially valuable: because their value never changes after initialisation, several threads can read them at the same time without needing explicit synchronisation — a common pattern to rule out race conditions (faulty results from simultaneous, uncoordinated access) from the outset, instead of preventing them afterwards with locks.
See also: Declaring Variables