Mastering the final Keyword in Java: Constants, Immutability, and More

Arshi Saxena - Oct 18 - - Dev Community

The final keyword is one of the most fundamental tools for creating constants and ensuring immutability in Java. However, it’s more than just declaring variables that can’t change. In this post, we’ll explore the key aspects of the final keyword in different contexts and its impact on variables, static fields, and constructors.

1. Final with Variables

Using final with variables ensures that once a value is assigned, it cannot be changed later. Here's a quick breakdown:

  • Constant Naming Convention: Use UPPERCASE names (e.g., COUNT).
  • Initialization Requirements: Must be initialized either at declaration or in constructor.
  • All Constructors Must Initialize: If initialized in the constructor, every constructor must assign a value.
  • No Setters: Setters cannot be generated for final variables since they’re immutable.
final int COUNT;  
final char GENDER = 'F'; // Initialized at declaration

public FinalKeyword() {
  // Initialized in Constructor
  COUNT = 90;

  // This will give a compile error
  // once initialized during declaration, cannot be changed
  GENDER = 'M'; 
}
Enter fullscreen mode Exit fullscreen mode

In the example above:

  • COUNT is not initialized at the time of declaration, meaning it must be initialized in the constructor.
  • GENDER is initialized with 'F' and cannot be changed anywhere else.

2. Final with Static Variables

A static final variable must be initialized at the time of declaration or in a static block. Unlike instance variables, static final fields cannot be initialized in the constructor because:

  • Static variables belong to the class, not to individual instances.
  • Final enforces immutability, meaning their values cannot be modified, even by instances.
static final int ID = 1;  
static final int DEPT;  

static {
    DEPT = 90; // Initialized in static block
}
Enter fullscreen mode Exit fullscreen mode

Why Can't Static Final Variables Be Initialized in Constructors?

Since constructors are called when instances are created, and static variables are associated with the class (not instances), it’s not possible to initialize or modify them inside a constructor.


3. Static Variables vs Static Final Variables

Static variables without final can be modified even inside constructors.

static int salary; // Default value 0 at class loading

public FinalKeyword() {
    salary = 10; // Static variable modified in constructor
}
Enter fullscreen mode Exit fullscreen mode

Key Differences

  • Static variables are shared across instances and can be modified by any of them.
  • Static final variables are immutable and shared by all instances, ensuring they remain constant throughout the program.

4. Constructor Requirements for Final Variables

When a final variable is not initialized at the time of declaration, it must be initialized in all constructors to avoid a compile-time error.

public FinalKeyword() {
    COUNT = 90; // Initialized in default constructor
}

public FinalKeyword(int count) {
    COUNT = count; // Initialized in parameterized constructor
}
Enter fullscreen mode Exit fullscreen mode

If a constructor does not initialize a final variable, the compiler will throw an error, ensuring the value is always assigned exactly once.


4. Comparison of Final Keyword Usage in Methods and Classes

Usage Effect Example
Final Method Cannot be overridden in subclasses. public final void getType() in java.lang.Object
Final Class Cannot be inherited by any class. java.lang.String, java.lang.Math
  • Final Methods: A final method ensures that subclasses cannot override it, enforcing consistent behavior across all instances. This is useful for methods like getType() in Object, which ensures critical functionality is not altered.
  • Final Classes: Declaring a class as final (e.g., String or Math) ensures that no subclass can alter its behavior, maintaining data integrity and preventing misuse.

Conclusion

The final keyword is a powerful tool in Java to enforce immutability and prevent unintended modifications. It plays a crucial role in defining constants, ensuring class-level consistency, and making code easier to understand and maintain.

Stay tuned for other posts in this series, where we’ll cover more Java keywords in depth to help you master the nuances of the language!


Related Posts

Happy Coding!

. . . . . . . . . . . . . . . . . . . . . . . . . . . . .