1. Introduction
When developing in Java, one of the keywords you will frequently encounter is final. However, what final actually means and when it should be used is often unclear—not only for beginners, but even for developers who are already somewhat familiar with Java.
In short, final means “prevent further modification.” It can be applied to variables, methods, and classes, and depending on how it is used, it can greatly improve the robustness and safety of your program.
For example, it helps prevent accidental reassignment of values, or prohibits unintended inheritance and method overriding, thereby avoiding unexpected bugs and defects. Additionally, using final correctly makes it clear to other developers that “this part must not be changed,” which is extremely useful in team development.
In this way, final is an essential keyword for designing safe and explicit Java programs. This article explains final from the basics to advanced usage and common pitfalls, with practical code examples. It is useful not only for those who are new to Java, but also for developers who want to revisit and organize their understanding of final.
2. Basic Overview of the final Keyword
The Java final keyword applies the constraint “cannot be changed anymore” in various situations. This section explains how final is used, starting from the basics.
2.1 Applying final to Variables
When final is applied to a variable, it can be assigned a value only once. After that, reassignment is not allowed.
Primitive types:
final int number = 10;
number = 20; // Error: cannot be reassigned because a value is already setReference types:
final List<String> names = new ArrayList<>();
names = new LinkedList<>(); // Error: cannot assign a different object
names.add("Alice"); // OK: the contents of the object can be modifiedConstant declarations (static final):
In Java, constants that are both immutable and globally shared are declared using static final.
public static final int MAX_USER = 100;Such values are shared across the class and treated as constants. By convention, they are written in uppercase letters with underscores.
2.2 Applying final to Methods
When a method is declared as final, it cannot be overridden in subclasses. This is useful when you want to fix a method’s behavior or maintain a safe inheritance structure.
public class Animal {
public final void speak() {
System.out.println("The animal makes a sound");
}
}
public class Dog extends Animal {
// public void speak() { ... } // Error: cannot override
}2.3 Applying final to Classes
When a class itself is declared final, it cannot be inherited.
public final class Utility {
// methods and variables
}
// public class MyUtility extends Utility {} // Error: inheritance not allowedFinal classes are often used when you want to prevent any modification or extension, such as for utility classes or strictly controlled designs.
Summary
As shown above, the final keyword expresses a strong intention of “no change” in Java programs. Its role and appropriate usage differ depending on whether it is applied to variables, methods, or classes, so it is important to use it with clear intent.
3. Proper Usage and Advanced Techniques for final
The final keyword is not only about preventing changes; it is also a powerful tool for writing safer and more efficient code in real-world development. This section introduces practical usage patterns and advanced techniques.
3.1 Benefits of Using final for Local Variables and Method Parameters
final can be applied not only to fields and classes, but also to local variables and method parameters. This explicitly indicates that a variable must not be reassigned within its scope.
public void printName(final String name) {
// name = "another"; // Error: reassignment not allowed
System.out.println(name);
}Using final for local variables helps prevent unintended reassignment at compile time. Additionally, when using variables from outer scopes in lambdas or anonymous classes, they must be final or effectively final.
public void showNames(List<String> names) {
final int size = names.size();
names.forEach(n -> System.out.println(size + ": " + n));
}3.2 A Common Pitfall with Reference Types and final
One of the most confusing points for many Java developers is applying final to reference variables. While reassignment of the reference is prohibited, the contents of the referenced object can still be modified.
final List<String> items = new ArrayList<>();
items.add("apple"); // OK: modifying the contents
items = new LinkedList<>(); // NG: reassignment not allowedTherefore, final does not mean “completely immutable.” If you want the contents to be immutable as well, you must combine it with immutable class design or utilities such as Collections.unmodifiableList.
3.3 Best Practices: Knowing When to Use final
- Use
finalproactively for constants and values that should never be reassigned
This clarifies intent and reduces potential bugs. - Use
finalon methods and classes to express design intent
It is effective when you want to prohibit inheritance or overriding. - Avoid overuse
Excessive use offinalcan reduce flexibility and make future refactoring harder. Always consider why you are making somethingfinal.
3.4 Improving Code Quality and Safety
Effective use of final significantly improves code readability and safety. By preventing unintended changes and clearly expressing design intent, the final keyword is widely recommended in many Java development environments.
4. Best Practices and Performance Considerations
The final keyword is used not only to prevent modification, but also from the perspectives of design and performance. This section introduces best practices and performance-related considerations.
4.1 final for Constants, Methods, and Classes in Clean Code
finalconstants (static final)
Defining frequently used or immutable values asstatic finalensures consistency across the application. Typical examples include error messages, limits, and global configuration values.
public static final int MAX_RETRY = 3;
public static final String ERROR_MESSAGE = "An error has occurred.";- Why use
finalon methods and classes
Declaring them asfinalexplicitly indicates that their behavior must not change, reducing the risk of accidental modification by others or your future self.
4.2 JVM Optimization and Performance Impact
The final keyword can provide performance benefits. Because the JVM knows that final variables and methods will not change, it can perform optimizations such as inlining and caching more easily.
However, modern JVMs already perform advanced optimizations automatically, so performance improvements from final should be considered secondary. The primary goals remain design clarity and safety.
4.3 Improving Thread Safety
In multithreaded environments, unexpected state changes can cause subtle bugs. By using final to ensure values do not change after initialization, you can significantly improve thread safety.
public class Config {
private final int port;
public Config(int port) {
this.port = port;
}
public int getPort() { return port; }
}This immutable object pattern is a fundamental approach to thread-safe programming.
4.4 Avoid Overuse: Balanced Design Matters
Although final is powerful, it should not be applied everywhere.
- Making parts
finalthat may require future extension can reduce flexibility. - If the design intent behind
finalis unclear, it may actually hurt maintainability.
Best practice:
- Apply
finalonly to parts that must never change - Avoid
finalwhere future extension or redesign is expected
5. Common Mistakes and Important Notes
While the final keyword is useful, incorrect usage can lead to unintended behavior or overly rigid designs. This section summarizes common mistakes and points to watch out for.
5.1 Misunderstanding Reference Types
Many developers mistakenly believe that final makes an object completely immutable. In reality, it only prevents reassignment of the reference; the contents of the object can still be modified.
final List<String> names = new ArrayList<>();
names.add("Sato"); // OK
names = new LinkedList<>(); // NG: reassignment not allowedTo make contents immutable, use immutable classes or collections such as Collections.unmodifiableList().

5.2 Cannot Be Combined with Abstract Classes or Interfaces
Since final prohibits inheritance and overriding, it cannot be combined with abstract classes or interfaces.
public final abstract class Sample {} // Error: cannot use abstract and final together5.3 Overusing final Reduces Extensibility
Applying final everywhere in pursuit of robustness can make future changes and extensions difficult. Design intent should be clearly shared within the team.
5.4 Forgetting Initialization in Initializers or Constructors
final variables must be assigned exactly once. They must be initialized either at declaration or in a constructor.
public class User {
private final String name;
public User(String name) {
this.name = name; // required initialization
}
}5.5 “Effectively Final” Requirement in Lambdas and Anonymous Classes
Variables used inside lambdas or anonymous classes must be final or effectively final (not reassigned).
void test() {
int x = 10;
Runnable r = () -> System.out.println(x); // OK
// x = 20; // NG: reassignment breaks effectively final rule
}Summary
- Use
finalwith clear intent. - Avoid misunderstandings and overuse to maintain safety and extensibility.
6. Practical Code Examples and Use Cases
After understanding how final works, seeing practical use cases helps reinforce the concept. Here are common real-world examples.
6.1 Constant Declarations with static final
public class MathUtil {
public static final double PI = 3.141592653589793;
public static final int MAX_USER_COUNT = 1000;
}6.2 Examples of Final Methods and Final Classes
Final method example:
public class BasePrinter {
public final void print(String text) {
System.out.println(text);
}
}
public class CustomPrinter extends BasePrinter {
// Cannot override print
}Final class example:
public final class Constants {
public static final String APP_NAME = "MyApp";
}6.3 Using final for Method Parameters and Local Variables
public void process(final int value) {
// value = 100; // Error
System.out.println("Value is " + value);
}6.4 Immutable Object Pattern
public final class User {
private final String name;
private final int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() { return name; }
public int getAge() { return age; }
}6.5 Combining Collections with final
public class DataHolder {
private final List<String> items;
public DataHolder(List<String> items) {
this.items = Collections.unmodifiableList(new ArrayList<>(items));
}
public List<String> getItems() {
return items;
}
}7. Conclusion
The Java final keyword is an essential mechanism for expressing immutability, preventing reassignment, and prohibiting inheritance or overriding.
Its main benefits include improved safety, clearer design intent, and potential performance and thread-safety improvements.
However, final should be applied thoughtfully. Understanding reference behavior and using it only where appropriate leads to robust and maintainable Java programs.
final is a partner for writing robust and readable code. Both beginners and experienced developers can benefit from revisiting its proper usage.
8. FAQ (Frequently Asked Questions)
Q1. Does using final make Java programs faster?
A. In some cases, JVM optimizations may improve performance, but the primary benefit is safety and clarity, not speed.
Q2. Are there disadvantages to using final on methods or classes?
A. Yes. It prevents extension through inheritance or overriding, which may reduce flexibility in future redesigns.
Q3. Can the contents of a final reference variable be changed?
A. Yes. The reference is immutable, but the object’s internal state can still change.
Q4. Can final and abstract be used together?
A. No. They represent opposite design intentions and cause a compile-time error.
Q5. Should method parameters and local variables always be final?
A. Use final when reassignment should be prevented, but avoid forcing it everywhere unnecessarily.
Q6. Are there restrictions on variables used in lambdas?
A. Yes. Variables must be final or effectively final.
Q7. Is it a problem to overuse final?
A. Overuse can reduce flexibility and extensibility. Apply it only where immutability is truly required.

