final Keyword in Java – Variables, Methods and Classes
The final keyword means "cannot be changed". It can be applied to variables (which then cannot be reassigned), methods (which cannot be overridden) and classes (which cannot be extended). Used well, final makes code safer, clearer and easier to reason about, especially in multithreaded programs.
This tutorial covers every use of final, including blank finals, constants, effectively final variables in lambdas, and how final helps build immutable objects.
1. final at a Glance
| Applied to | Meaning | Example |
|---|---|---|
| Local variable or parameter | Can be assigned only once | final double gst = 0.18; |
| Field | Must be assigned exactly once, by the end of construction | private final String id; |
static final field | A class-level constant | static final int MAX = 3; |
| Method | Cannot be overridden by subclasses | final double fee(...) |
| Class | Cannot be extended | final class Currency |
2. final Variables and Constants
import java.util.ArrayList;
import java.util.List;
public class FinalVariables {
static final int MAX_LOGIN_ATTEMPTS = 3; // constant: static final
private final String id; // final field: assigned exactly once
FinalVariables(String id) {
this.id = id; // blank final assigned in the constructor
}
public static void main(String[] args) {
final double gst = 0.18; // final local variable
// gst = 0.12; // compile error
final int discount; // blank final local: assigned once later
discount = args.length > 0 ? 20 : 10;
System.out.println("discount = " + discount + ", gst = " + gst + ", max attempts = " + MAX_LOGIN_ATTEMPTS);
// final reference: the list object can still change
final List<String> cart = new ArrayList<>();
cart.add("pen");
cart.add("book");
// cart = new ArrayList<>(); // compile error: cannot reassign
System.out.println("cart = " + cart);
System.out.println("id = " + new FinalVariables("USR-42").id);
}
}
discount = 10, gst = 0.18, max attempts = 3 cart = [pen, book] id = USR-42
- A blank final is declared without a value and assigned exactly once later, in every code path (for fields: in every constructor or an initialiser).
- Constants are
static finalfields with values known at compile time, named inUPPER_SNAKE_CASE. - A final reference cannot point to another object, but the object itself may still change, as the cart list shows.
finaldoes not make objects immutable on its own.
3. final Methods and final Classes
A final method protects behaviour that subclasses must not change; a final class cannot have subclasses at all:
public class FinalMethodsClasses {
static class Payment {
// final: subclasses must not change how the fee is calculated
final double fee(double amount) { return amount * 0.02; }
String type() { return "generic"; }
}
static class CardPayment extends Payment {
@Override String type() { return "card"; } // allowed
// @Override double fee(double amount) { ... } // compile error: cannot override final method
}
static final class Currency { // final class: cannot be extended
final String code;
Currency(String code) { this.code = code; }
}
// static class Crypto extends Currency { } // compile error: cannot inherit from final
public static void main(String[] args) {
Payment p = new CardPayment();
System.out.println(p.type() + " payment fee on 1000 = " + p.fee(1000));
System.out.println("currency = " + new Currency("INR").code);
System.out.println("String is final: " + java.lang.reflect.Modifier.isFinal(String.class.getModifiers()));
}
}
card payment fee on 1000 = 20.0 currency = INR String is final: true
Many core classes are final, including String, Integer and the other wrappers, and LocalDate. This guarantees that a String always behaves like a String, which is important for security and for using strings as map keys. Since Java 17, sealed classes offer a middle ground: extension limited to listed subclasses.
4. Effectively Final Variables
Lambdas and anonymous classes can use local variables from the enclosing method only if those variables are final or effectively final, meaning they are never reassigned after initialisation, even without the keyword:
import java.util.List;
public class EffectivelyFinal {
public static void main(String[] args) {
String prefix = "Item: "; // never reassigned: "effectively final"
List.of("pen", "cup").forEach(item -> System.out.println(prefix + item));
int counter = 0;
// List.of("a").forEach(x -> counter++); // compile error: counter is not effectively final
for (String s : List.of("a", "b", "c")) counter++; // use a normal loop instead
System.out.println("counter = " + counter);
}
}
Item: pen Item: cup counter = 3
This rule exists because lambdas may run later, possibly on another thread, so they capture a copy of the value, which must not change.
5. Using final to Build Immutable Objects
An immutable object cannot change after it is created. final is a key ingredient:
import java.util.List;
public class ImmutableClass {
// final class + private final fields + no setters + defensive copy = immutable
static final class Order {
private final String id;
private final List<String> items;
Order(String id, List<String> items) {
this.id = id;
this.items = List.copyOf(items); // copy: the caller's list cannot change us
}
String id() { return id; }
List<String> items() { return items; } // already unmodifiable
Order withItem(String item) { // "modify" by creating a new object
List<String> more = new java.util.ArrayList<>(items);
more.add(item);
return new Order(id, more);
}
}
public static void main(String[] args) {
Order o1 = new Order("A1", List.of("pen"));
Order o2 = o1.withItem("book");
System.out.println(o1.id() + " " + o1.items());
System.out.println(o2.id() + " " + o2.items());
}
}
A1 [pen] A1 [pen, book]
- Make the class
finalso subclasses cannot add mutable behaviour. - Make all fields
private final. - Provide no setters; return new objects for "changes".
- Defensively copy mutable inputs and never expose mutable internals.
Records follow most of these rules automatically. Immutable objects are thread-safe and can be shared freely. Final fields also have a special guarantee in the Java Memory Model: once a constructor finishes, other threads see their correct values.
6. Rules and Notes
- An uninitialised final field causes a compile error ("variable might not have been initialized").
- Final static fields can be assigned in a
staticinitializer block. - Constructors cannot be final;
abstractandfinalcannot be combined on a method or class. privatemethods are implicitly final, because they cannot be overridden.- Final parameters cannot be reassigned inside the method.
7. Summary
- final variables can be assigned once;
static finalfields are constants. - final methods cannot be overridden; final classes cannot be extended.
- A final reference fixes the reference, not the object's contents.
- Lambdas can capture only final or effectively final local variables.
- final fields are central to immutable, thread-safe classes.
Related Tutorials
Frequently Asked Questions (FAQ)
Q1. What is the final keyword in Java?
A modifier meaning "cannot change": final variables cannot be reassigned, final methods cannot be overridden, and final classes cannot be extended.
Q2. What is a blank final variable?
A final variable declared without an initial value and assigned exactly once later, for example a final field assigned in the constructor.
Q3. Can a final variable be changed?
No, it cannot be reassigned. If it refers to a mutable object, the object's contents can still change.
Q4. What is the difference between final and immutable?
final applies to a variable and stops reassignment. Immutability applies to an object and means its state never changes. A final reference to a mutable list still allows adding elements.
Q5. How do I declare a constant in Java?
Use public static final with an uppercase name: public static final int MAX_USERS = 100;.
Q6. Can a final method be overloaded?
Yes. final only prevents overriding in subclasses; methods with the same name but different parameters can still be declared.
Q7. Can a final method be inherited?
Yes. Subclasses inherit and can call it; they just cannot override it.
Q8. Why is String a final class?
To guarantee that strings are immutable and behave consistently, which matters for security (class loading, file paths), caching of hash codes, the string pool and use as map keys.
Q9. Can a constructor be final?
No. Constructors are never inherited or overridden, so final has no meaning and is not allowed.
Q10. Can an abstract class be final?
No. An abstract class must be extended to be used, which contradicts final. The compiler rejects the combination.
Q11. What is an effectively final variable?
A local variable that is never reassigned after its initialisation, even without the final keyword. Lambdas and anonymous classes can use such variables.
Q12. Why can't lambdas modify local variables?
Lambdas capture a copy of local variables and might run later or on another thread. Requiring effectively final variables avoids confusing and unsafe behaviour.
Q13. Are private methods final?
Effectively yes. Private methods are not visible to subclasses and cannot be overridden, so adding final is redundant.
Q14. Does final improve performance?
Rarely in a noticeable way; modern JITs optimise well without it. Compile-time constants (static final primitives and strings) are inlined. Use final mainly for clarity and safety.
Q15. Can a final field be assigned in a method?
No. Instance final fields must be assigned in a constructor, initializer block or declaration; static final fields in the declaration or a static block.
Q16. Can I use final in method parameters?
Yes. It prevents reassigning the parameter inside the method. Some teams use it consistently; others rely on effectively final semantics.
Q17. What is the difference between final and sealed classes?
A final class cannot be extended at all. A sealed class (Java 17+) can be extended only by the subclasses it lists in its permits clause.
Q18. How do final fields help with thread safety?
The Java Memory Model guarantees that once an object is fully constructed, all threads see the correct values of its final fields without extra synchronization, provided this did not escape during construction.
Q19. Can a final array be modified?
Its elements can be changed (arr[0] = 5;), but the variable cannot be pointed to a different array.
Q20. Is final the same as const in C++?
Not exactly. Java's final stops reassignment of the variable but does not make the referenced object read-only. const is a reserved but unused keyword in Java.