final (Java)
A keyword that makes variables, methods, and classes "immutable" or "non-overridable". Applying final to a variable prevents reassignment; applying it to a method prevents overriding in subclasses; applying it to a class prevents inheritance. For constant definitions, combining static final is the conventional approach.
Syntax
// final local variable: cannot be reassigned once a value is set
final int MAX_LEVEL = 100;
// final field: initialized in the constructor or at the point of declaration
class Hero {
final String name; // Initialized in the constructor
Hero(String name) {
this.name = name; // Can be assigned exactly once here
}
}
// static final (class constant): conventionally named in UPPER_SNAKE_CASE
static final int MAX_POWER = 9000;
// final method: cannot be overridden in a subclass
final void specialMove() {
// implementation
}
// final class: cannot be extended
final class Scouter {
// implementation
}
Uses of final
| Target | Effect | Common use |
|---|---|---|
| Local variable | Cannot be reassigned after declaration. | Prevent unintended modification. Required for variables referenced inside a lambda expression. |
| Field | Cannot be reassigned after the constructor completes. | Designing immutable objects. Guaranteeing that a value does not change after initialization. |
| static final (constant) | A class-level field that cannot be changed. | Eliminating magic numbers. Giving a meaningful name to a constant value. |
| Method parameter | The parameter variable cannot be reassigned inside the method. | Preventing accidental overwriting of arguments to reduce bugs. |
| Method | Cannot be overridden in a subclass. | Protecting behavior that must not be changed through inheritance. |
| Class | The class cannot be extended. | Guaranteeing immutability by design (e.g., the String class). |
Sample Code
FinalVariable.java
public class FinalVariable {
public static void main(String[] args) {
// --- final local variable ---
final String hero = "孫悟空";
// hero = "ベジータ"; // Compile error: cannot reassign a final variable
// --- static final constant ---
// MAX_POWER is already defined as a class constant
System.out.println(hero + "'s max power: " + Saiyan.MAX_POWER);
// --- Using a class with final fields ---
Saiyan s1 = new Saiyan("ベジータ", 8000);
Saiyan s2 = new Saiyan("フリーザ", 12000);
System.out.println(s1.name + ": " + s1.power);
System.out.println(s2.name + ": " + s2.power);
// s1.name = "ナッパ"; // Compile error: cannot modify a final field
// --- final method parameter ---
printStatus("クリリン", 1500);
}
// final parameter: prevents accidental reassignment of the argument inside the method
static void printStatus(final String name, final int power) {
// name = "亀仙人"; // Compile error: cannot reassign a final parameter
System.out.println(name + "'s power is " + power + ".");
}
}
// --- Class with static final constants and final fields ---
class Saiyan {
// Class constants (static final): named in UPPER_SNAKE_CASE
static final int MAX_POWER = 9000;
static final String RACE = "サイヤ人";
// final fields: can be initialized exactly once in the constructor
final String name;
final int power;
Saiyan(String name, int power) {
this.name = name;
this.power = power;
}
}
javac FinalVariable.java java FinalVariable 孫悟空's max power: 9000 ベジータ: 8000 フリーザ: 12000 クリリン's power is 1500.
FinalMethod.java
public class FinalMethod {
public static void main(String[] args) {
SuperSaiyan goku = new SuperSaiyan("孫悟空");
SuperSaiyan vegeta = new SuperSaiyan("ベジータ");
goku.transform(); // Calls the overridden method in the subclass
vegeta.transform();
goku.kamehameha(); // final methods cannot be overridden
vegeta.kamehameha();
}
}
// Parent class
class Fighter {
String name;
Fighter(String name) {
this.name = name;
}
// final method: cannot be overridden in a subclass
final void kamehameha() {
System.out.println(name + " fires a Kamehameha! (final method)");
}
// Regular method: can be overridden in a subclass
void transform() {
System.out.println(name + " is in base form.");
}
}
// Subclass
class SuperSaiyan extends Fighter {
SuperSaiyan(String name) {
super(name);
}
// transform is not final, so it can be overridden
@Override
void transform() {
System.out.println(name + " transformed into a Super Saiyan!");
}
// kamehameha is final, so attempting to override it causes a compile error
// @Override
// void kamehameha() { } // Compile error: cannot override a final method
}
javac FinalMethod.java java FinalMethod 孫悟空 transformed into a Super Saiyan! ベジータ transformed into a Super Saiyan! 孫悟空 fires a Kamehameha! (final method) ベジータ fires a Kamehameha! (final method)
FinalClass.java
public class FinalClass {
public static void main(String[] args) {
DragonBall db = new DragonBall(7, "地球のドラゴンボール");
System.out.println("Collect " + db.count + " of " + db.name + " to have your wish granted.");
db.display();
}
}
// final class: cannot be extended
final class DragonBall {
final int count;
final String name;
DragonBall(int count, String name) {
this.count = count;
this.name = name;
}
void display() {
System.out.println("[" + name + "] — " + count + " in total");
}
}
// Attempting to extend DragonBall causes a compile error
// class NamekDragonBall extends DragonBall { } // Compile error: cannot inherit from final class
javac FinalClass.java java FinalClass Collect 7 of 地球のドラゴンボール to have your wish granted. [地球のドラゴンボール] — 7 in total
EffectivelyFinal.java
import java.util.List;
public class EffectivelyFinal {
public static void main(String[] args) {
// --- Effectively final ---
// The Java compiler treats a variable that is never modified after declaration
// as "effectively final".
// A lambda expression can only reference variables that are final or effectively final.
String villain = "フリーザ"; // Not declared final, but never modified — effectively final
// The lambda can reference the outer variable villain
Runnable announcement = () ->
System.out.println(villain + " is attacking!");
announcement.run();
// villain = "セル"; // Uncommenting this line causes a compile error on the lambda above
// → "Variable used in lambda expression should be final or effectively final"
// --- Example: print list elements with a lambda ---
List<String> fighters = List.of("孫悟空", "ベジータ", "ピッコロ", "クリリン");
// threshold is never modified, so it is effectively final
int threshold = 5000;
fighters.forEach(name -> {
// name is a lambda parameter, so there is no issue
System.out.println(name + " (power threshold: " + threshold + ")");
});
}
}
javac EffectivelyFinal.java java EffectivelyFinal フリーザ is attacking! 孫悟空 (power threshold: 5000) ベジータ (power threshold: 5000) ピッコロ (power threshold: 5000) クリリン (power threshold: 5000)
Common Mistake 1: Applying final to a reference type still allows mutation of the object's internals
Applying final to a reference-type variable only prevents reassignment of the reference. The fields and contents of the referenced object can still be changed. Assuming that "making it final also freezes the contents" is a common source of bugs.
FinalRefNg.java
import java.util.ArrayList;
public class FinalRefNg {
public static void main(String[] args) {
// Even with final, the contents of the ArrayList can be changed
final ArrayList<String> fighters = new ArrayList<>();
fighters.add("孫悟空");
fighters.add("ベジータ");
// Elements can still be added despite final
fighters.add("フリーザ");
System.out.println(fighters); // [孫悟空, ベジータ, フリーザ]
// Reassigning the reference causes a compile error
// fighters = new ArrayList<>(); // NG: cannot assign a value to final variable
}
}
javac FinalRefNg.java java FinalRefNg [孫悟空, ベジータ, フリーザ]
To also prevent modification of the contents, use Collections.unmodifiableList() or List.of() (Java 9+) to create an immutable list.
FinalRefOk.java
import java.util.List;
import java.util.Collections;
import java.util.ArrayList;
public class FinalRefOk {
public static void main(String[] args) {
// A list created with List.of() is unmodifiable (Java 9+)
final List<String> fighters = List.of("孫悟空", "ベジータ", "ピッコロ");
System.out.println(fighters);
// fighters.add("フリーザ"); // Throws UnsupportedOperationException
// For Java 8 and earlier, use Collections.unmodifiableList()
ArrayList<String> src = new ArrayList<>();
src.add("孫悟空");
src.add("ベジータ");
final List<String> immutable = Collections.unmodifiableList(src);
System.out.println(immutable);
}
}
javac FinalRefOk.java java FinalRefOk [孫悟空, ベジータ, ピッコロ] [孫悟空, ベジータ]
Common Mistake 2: Violating the naming convention for static final constants
Constants defined with static final should conventionally be named in UPPER_SNAKE_CASE (all uppercase, words separated by underscores). Using lowercase camelCase compiles fine but makes it hard to distinguish constants from variables at a glance.
ConstNamingNg.java
public class ConstNamingNg {
// Non-conventional naming (compiles but is hard to read)
static final int maxPower = 9000; // NG: indistinguishable from a variable
static final String raceName = "サイヤ人"; // NG: does not look like a constant
public static void main(String[] args) {
System.out.println("Max power: " + maxPower);
System.out.println("Race: " + raceName);
}
}
javac ConstNamingNg.java java ConstNamingNg Max power: 9000 Race: サイヤ人
Naming static final constants in UPPER_SNAKE_CASE makes it immediately clear in code that they are constants, not variables.
ConstNamingOk.java
public class ConstNamingOk {
// UPPER_SNAKE_CASE makes it obvious at a glance that these are constants
static final int MAX_POWER = 9000;
static final String RACE_NAME = "サイヤ人";
public static void main(String[] args) {
System.out.println("Max power: " + MAX_POWER);
System.out.println("Race: " + RACE_NAME);
}
}
javac ConstNamingOk.java java ConstNamingOk Max power: 9000 Race: サイヤ人
Notes
The most fundamental use of final is defining constants with static final. By convention, constant names are written in UPPER_SNAKE_CASE (uppercase snake case). Replacing magic numbers with named constants makes the intent of code clearer and improves maintainability.
A class with final fields is useful for designing "immutable objects" whose state does not change after instantiation. Immutable objects are thread-safe and less prone to unexpected side effects. Java's String class is itself a final class.
"Effectively final" refers to a local variable that is never modified after its declaration, even without the explicit final keyword. To reference a local variable from inside a lambda expression, that variable must be final or effectively final. Attempting to modify the variable after it is referenced by a lambda causes a compile error.
For access modifiers and static, see public / private / protected / static / final. For inheritance, see extends / super / @Override. For lambda expressions, see Lambda Expressions / Method References.
If you find any errors or copyright issues, please contact us.