As Java developers, we often face challenges in maintaining the integrity and predictability of our code. Have you ever wondered how to make sure certain parts of your Java code never change?
Maybe you’re worried about accidental changes to important variables. Or you’re trying to lock down methods and classes to prevent future bugs. These are common worries for Java developers.
Ensuring that certain variables remain unchanged, methods retain their behaviour, and classes are not extended can be critical for the stability of our applications.
This is where the final keyword in Java comes into play. The final keyword is a versatile tool that allows us to impose restrictions on variables, methods, and classes. It helps us create constants, protect methods from being overridden, and prevent classes from being extended.
In this blog, we’ll explore the various uses of the final keyword in Java, providing detailed examples and explanations to help you understand its benefits and applications.
The Role of Final Variables in Java
Characteristics of Final Variables
A final variable in Java is like setting a rule: once it’s set, it can’t be changed. This is perfect for values that must remain constant, like mathematical constants or configuration values.
Once we assign a value to a final variable, it sticks. We can’t change it later, making our code more reliable and predictable.
Initialising Final Variables
We have several ways to initialise the final variables:
At the time of declaration.
Inside an instance initialiser block.
Inside the constructor.
Example:
import java.util.Scanner;
public class Constants {
final int MAX_USERS = 100;
final double PI;
// Constructor
public Constants() {
this.PI = 3.14159;
}
public static void main(String[] args) {
Constants constants = new Constants();
System.out.println("Max Users: " + constants.MAX_USERS);
System.out.println("Value of PI: " + constants.PI);
}
}
Output:
This example shows how to set final variables. MAX_USERS is set when declared. PI is set in the constructor.
Blank Final Variables
Blank final variables are a bit different. They’re declared but not immediately assigned. We must assign them in the constructor or an initialiser block.
Example:
import java.util.Scanner;
public class Config {
final int TIMEOUT;
// Constructor
public Config(int timeout) {
this.TIMEOUT = timeout;
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("Enter timeout value: ");
int timeout = scanner.nextInt();
Config config = new Config(timeout);
System.out.println("Configured Timeout: " + config.TIMEOUT);
}
}
Output:
Here, we set TIMEOUT in the constructor based on user input.
Static Final Variables
Static final variables are shared by all instances of a class. They are constants and must be initialised in a static block or at declaration.
Example:
public class MathConstants {
static final double E;
static {
E = 2.71828;
}
public static void main(String[] args) {
System.out.println("Value of E: " + E);
}
}
Output:
This example sets the value of E in a static block, making it a constant for the class.
Final Reference Variables
Final reference variables can’t be reassigned to another object. However, we can still modify the internal state of the object they reference.
Example:
import java.util.Scanner;
public class FinalReferenceExample {
final StringBuilder message = new StringBuilder("Hello");
public void appendMessage(String extra) {
message.append(extra);
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("Enter text to append: ");
String extra = scanner.nextLine();
FinalReferenceExample example = new FinalReferenceExample();
example.appendMessage(extra);
System.out.println("Updated Message: " + example.message);
}
}
Output:
We can see that the final reference variable message is modified by appending text to it.
Get curriculum highlights, career paths, industry insights and accelerate your technology journey.
Download brochure
Utilising the Final Keyword with Methods
Final methods can’t be overridden by subclasses. This ensures the method’s behaviour stays the same across all instances.
Example:
class Vehicle {
final void startEngine() {
System.out.println("Engine started.");
}
public static void main(String[] args) {
Vehicle vehicle = new Vehicle();
vehicle.startEngine();
// Testing the Car class
Car car = new Car();
car.display();
}
}
class Car extends Vehicle {
void display() {
System.out.println("This is a car.");
}
// Uncommenting the below method will cause a compile-time error
// void startEngine() {
// System.out.println("Car engine started.");
// }
}
Output:
In this example, the startEngine method in the Vehicle class is final. This means that any subclass, like Car, cannot override it. Trying to do so will result in a compile-time error.
Do you ever worry about your classes being extended and changed in ways you didn’t intend? Final classes in Java can help you with that.
They stop other classes from extending them, keeping your design intact.
Final classes are crucial when we want to create immutable classes or prevent changes. For example, the String class in Java is final. This ensures no one can alter its behaviour.
Example:
public final class MathConstants {
public static final double E = 2.71828;
public static final double PI = 3.14159;
public static void main(String[] args) {
System.out.println("Value of E: " + E);
System.out.println("Value of PI: " + PI);
}
}
// This will cause a compile-time error
// public class MyConstants extends MathConstants {
// }
Output:
Here, the MathConstants class is final. No other class can extend it. This keeps the constants safe and unchanged.
Performance Implications of Using the Final Keyword
Are you concerned about the performance of your Java code? Using the final keyword can help.
It allows the JVM to optimise your code better. When the JVM knows that certain values or methods won’t change, it can make your program run faster.
How Does the Final Keyword Boost Performance?
Method Inlining: Final methods can be inlined, reducing the overhead of method calls.
Constant Folding: Final variables allow the compiler to replace variables with their values during compilation.
Using final in these ways can lead to noticeable performance improvements.
Best Practices and Conventions for Using Final in Java
Wondering how to use the final keyword effectively? Here are some best practices to follow.
Naming Conventions
Use uppercase letters for final variables that represent constants.
Separate words with underscores (_).
Example:
public class NamingConventions {
public static final double GRAVITY = 9.8;
public static void main(String[] args) {
System.out.println("Gravity: " + GRAVITY);
}
}
Output:
Initialisation Best Practices
Initialise final variables as soon as possible.
Prefer initialisation at the time of declaration.
Example:
public class Initialisation {
final int MAX_USERS = 100;
final double PI;
// Constructor
public Initialisation() {
this.PI = 3.14159;
}
public static void main(String[] args) {
Initialisation init = new Initialisation();
System.out.println("Max Users: " + init.MAX_USERS);
System.out.println("Value of PI: " + init.PI);
}
}
Output:
Avoid Overuse
Don’t overuse the final keyword.
Use it when it makes sense for readability and design.
Security and Immutability
Use final for security-sensitive data.
Ensure critical data remains unchanged.
Example:
public final class SecurityConstants {
public static final String SECRET_KEY = "1234567890";
public static void main(String[] args) {
System.out.println("Secret Key: " + SECRET_KEY);
}
}
Output:
In this example, the SECRET_KEY remains unchanged and secure.
Advantages and Disadvantages of Using the Final Keyword
Are you unsure whether to use the final keyword in Java? Let’s break down the pros and cons to help you decide.
Advantages
Immutability
Final variables ensure that once assigned, the value cannot change. This makes your code more predictable and reliable.
Security
Using final can prevent unwanted modifications. This is especially useful for sensitive data.
Optimisation
The JVM can optimise code better when it knows that certain values and methods won’t change. This can improve performance.
Readability
Final variables and methods clearly signal that they are not meant to be modified. This makes your code easier to understand.
Method Inlining
Final methods can be inlined by the compiler, which can reduce the overhead of method calls.
Disadvantages
Limited Flexibility
Using final can restrict the flexibility of your code. Once something is final, you can’t change it or extend it.
Complex Initialisation
Blank final variables must be initialised in all constructors. This can be cumbersome and error-prone.
Overuse
Using final everywhere can clutter your code and make it harder to read. Use it only when it makes sense.
Non-Primitive Limitations
Final variables work well with primitive types but can be less effective with non-primitive types. While the reference can’t change, the object itself can.
Conclusion
Using the final keyword in Java can help us write more secure, efficient, and reliable code. By preventing changes to variables, methods, and classes, we maintain consistency in our applications.
Whether it’s ensuring a value remains constant or preventing methods from being overridden, the final keyword is a valuable tool.
By understanding its advantages and limitations, we can effectively use final to write more robust Java applications. Embrace these best practices, and keep your code secure, efficient, and maintainable.
FAQs
What is the purpose of the final keyword in Java?
The final keyword restricts modification to variables, methods, and classes. It ensures immutability and consistency.
Can a final method be inherited?
Yes, a final method can be inherited, but it cannot be overridden.
What is a blank final variable?
A blank final variable is a final variable that is not initialised during declaration. It must be initialised in the constructor.
Can we declare a final constructor?
No, constructors cannot be declared as final. Constructors are not inherited, so there's no point in making them final.
What happens if we try to reassign a final reference variable?
Attempting to reassign a final reference variable results in a compile-time error. The reference cannot change, but the object's internal state can.
Hero Vired is a leading LearnTech company dedicated to offering cutting-edge programs in collaboration with top-tier global institutions. As part of the esteemed Hero Group, we are committed to revolutionizing the skill development landscape in India. Our programs, delivered by industry experts, are designed to empower professionals and students with the skills they need to thrive in today’s competitive job market.