Java final Keyword Tutorial with Real-Life Project Example
Last Updated on: 14th Nov 2025 18:56:43 PM
Welcome to this beginner-friendly tutorial on the final keyword in Java! The final keyword is used to restrict modification of classes, methods, and variables. It ensures immutability, security, and design integrity.
This tutorial uses a real-world project-based example — a Secure Banking & Payroll System — to show how final is used in production software.
What is the final Keyword?
The final keyword in Java is a non-access modifier that restricts the user from modifying a class, method, or variable.
It is used to restrict modification — meaning once something is declared as final, it cannot be changed or overridden.
|
Applied To |
Effect |
|---|---|
|
Variable |
Value cannot be changed (constant) |
|
Method |
Cannot be overridden in subclass |
|
Class |
Cannot be extended (no inheritance) |
1. final with Variables (Constants)
A final variable is like a constant.Once assigned a value, it cannot be changed later.
Purpose:
-
Create immutable constants
-
Prevent accidental changes
-
Improve performance and security
Syntax:
final int speed = 90;
Here, speed is a constant — its value cannot be reassigned.
Example:
class Car {
final int speedLimit = 100; // final variable
void displaySpeed() {
System.out.println("Speed Limit: " + speedLimit);
// speedLimit = 120; // ❌ Error: cannot assign a value to final variable
}
}
public class Main {
public static void main(String[] args) {
Car obj = new Car();
obj.displaySpeed();
}
}
Output:
Speed Limit: 100
Note : Always initialize a final variable when declared, or in a constructor if it’s an instance variable.
Example: Banking Constants
// BankConfig.java
public class BankConfig {
// final variables = constants
public static final String BANK_NAME = "National Bank of India";
public static final double INTEREST_RATE_SAVINGS = 4.0;
public static final double INTEREST_RATE_FD = 7.5;
public static final int MIN_AGE_FOR_ACCOUNT = 18;
public static final double OVERDRAFT_LIMIT = 5000.0;
// Private final instance variable
private final String branchCode;
public BankConfig(String branchCode) {
this.branchCode = branchCode; // Can be set in constructor
}
public String getBranchCode() {
return branchCode;
}
}
Using final Variables in Payroll
// PayrollProcessor.java
public class PayrollProcessor {
// final local variable
public void calculateBonus(Employee emp) {
final double BONUS_PERCENT = 10.0; // Cannot be changed
double bonus = emp.getSalary() * (BONUS_PERCENT / 100);
// BONUS_PERCENT = 15.0; // COMPILE ERROR!
System.out.println("Bonus: ₹" + bonus);
}
}
2. final with Methods (Prevent Overriding)
A final method cannot be overridden by subclasses.
Purpose:
-
Lock method behavior
-
Ensure critical logic is not altered
-
Improve security and performance
Syntax:
class Parent {
final void show() {
System.out.println("Parent Class Method");
}
}
If a subclass tries to override this method, the compiler will throw an error.
Example:
class Parent {
final void display() {
System.out.println("This is a final method from Parent class");
}
}
class Child extends Parent {
// void display() { } ❌ Error: Cannot override final method
}
public class Main {
public static void main(String[] args) {
Child obj = new Child();
obj.display();
}
}
Output:
This is a final method from Parent class
Note : Use final methods when you want to prevent subclass modification of important methods (for example, core business logic or security-related code).
Example 2: Secure Transaction Method
// SecureAccount.java
public class SecureAccount {
protected double balance;
private final String accountNumber;
public SecureAccount(String accountNumber, double initialBalance) {
this.accountNumber = accountNumber;
this.balance = initialBalance;
}
// final method - cannot be overridden
public final boolean validateTransaction(double amount) {
if (amount <= 0) {
System.out.println("Invalid: Amount must be positive");
return false;
}
if (amount > 100000) {
System.out.println("High-value transaction requires approval");
return false;
}
return true;
}
// final method for audit log
public final void logTransaction(String type, double amount) {
System.out.println("[AUDIT] " + type + ": ₹" + amount +
" | Account: " + accountNumber +
" | Time: " + java.time.LocalDateTime.now());
}
public double getBalance() { return balance; }
}
Attempt to Override final Method (Will Fail)
// RiskyAccount.java - TRYING TO OVERRIDE final METHOD
public class RiskyAccount extends SecureAccount {
public RiskyAccount(String accNo, double bal) {
super(accNo, bal);
}
// COMPILE ERROR!
// @Override
// public boolean validateTransaction(double amount) {
// return true; // Bypassing security - NOT ALLOWED!
// }
}
3. final with Classes (Prevent Inheritance)
A final class cannot be inherited by any other class.
Purpose:
-
Seal the class design
-
Prevent subclassing for security
-
Enable compiler optimizations
Syntax:
final class Vehicle {
void display() {
System.out.println("Vehicle class");
}
}
Example:
final class Vehicle {
void run() {
System.out.println("Vehicle is running");
}
}
// class Car extends Vehicle { } ❌ Error: Cannot inherit from final class
public class Main {
public static void main(String[] args) {
Vehicle v = new Vehicle();
v.run();
}
}
Output:
Vehicle is running
Use final class when you want to secure your class from inheritance — e.g., utility or helper classes like java.lang.String.
Example: Immutable Transaction Record
// Transaction.java - final CLASS
public final class Transaction {
private final String transactionId;
private final double amount;
private final String type;
private final String timestamp;
private final String accountNumber;
// All fields final - immutable object
public Transaction(String transactionId, double amount, String type, String accountNumber) {
this.transactionId = transactionId;
this.amount = amount;
this.type = type;
this.accountNumber = accountNumber;
this.timestamp = java.time.LocalDateTime.now().toString();
}
// Only getters - no setters
public String getTransactionId() { return transactionId; }
public double getAmount() { return amount; }
public String getType() { return type; }
public String getTimestamp() { return timestamp; }
public String getAccountNumber() { return accountNumber; }
@Override
public String toString() {
return "Transaction{" +
"id='" + transactionId + '\'' +
", amount=" + amount +
", type='" + type + '\'' +
", time='" + timestamp + '\'' +
'}';
}
}
Attempt to Extend final Class (Will Fail)
// FakeTransaction.java - TRYING TO EXTEND final CLASS
// public class FakeTransaction extends Transaction { } // COMPILE ERROR!
Complete Project: Secure Banking System
// BankingSystem.java
import java.util.ArrayList;
import java.util.List;
public class BankingSystem {
public static void main(String[] args) {
System.out.println("SECURE BANKING SYSTEM\n");
// Using final constants
System.out.println("Bank: " + BankConfig.BANK_NAME);
System.out.println("Min Age: " + BankConfig.MIN_AGE_FOR_ACCOUNT + " years");
// Create secure account
SecureAccount acc1 = new SecureAccount("ACC001", 10000);
// final local variable
final double depositAmount = 5000;
// depositAmount = 6000; // ERROR!
// Test final method
if (acc1.validateTransaction(50000)) {
acc1.logTransaction("DEPOSIT", 50000);
}
if (acc1.validateTransaction(150000)) { // Blocked by final method
// Won't reach here
}
// Create immutable transaction
Transaction tx = new Transaction("TXN001", 3000, "CREDIT", "ACC001");
System.out.println(tx);
// List of transactions (immutable)
List<Transaction> auditLog = new ArrayList<>();
auditLog.add(tx);
// auditLog.get(0).amount = 5000; // ERROR! final field
System.out.println("\nSystem secure: final guarantees enforced!");
}
}
Output
SECURE BANKING SYSTEM
Bank: National Bank of India
Min Age: 18 years
Invalid: Amount must be positive
High-value transaction requires approval
Transaction{id='TXN001', amount=3000.0, type='CREDIT', time='2025-04-05T10:30:45.123'}
System secure: final guarantees enforced!
Why Use final? (Real Project Benefits)
|
Use Case |
Benefit |
|---|---|
|
final variables |
Constants, thread-safe, optimized |
|
final methods |
Security, prevent bugs, faster calls |
|
final classes |
Immutable design, security, performance |
Key Points to Remember
-
A final variable = constant → can’t be changed.
-
A final method = can’t be overridden.
-
A final class = can’t be inherited.
-
The final keyword helps make your code secure, consistent, and reliable.
Difference Between final, finally, and finalize()
| Keyword | Description | Used With |
|---|---|---|
| final | Prevents modification | Variables, Methods, Classes |
| finally | Used in exception handling (always executes) | try-catch block |
| finalize() | Called before garbage collection | Methods |
Best Practices
// Good: Constants in uppercase
public static final double PI = 3.14159;
// Good: final in immutable classes
public final class Config { }
// Good: final parameters (prevent change)
public void process(final String data) { }
Common Mistakes
// final reference - object can still change!
final List<String> list = new ArrayList<>();
list.add("item"); // OK!
list = new ArrayList<>(); // ERROR!
// final doesn't make object immutable
final StringBuilder sb = new StringBuilder();
sb.append("change"); // OK!
Real-Time Use Cases
|
System |
final Usage |
|---|---|
|
Banking |
final transaction rules, constants |
|
Configuration |
final config values |
|
Security |
final authentication methods |
|
Utilities |
final class Math, final method getClass() |
Summary
|
final On |
Effect |
Use When |
|---|---|---|
|
Variable |
Value cannot change |
Constants, config |
|
Method |
Cannot override |
Security, fixed logic |
|
Class |
Cannot extend |
Immutable, secure design |
Conclusion
The final keyword in Java adds an extra layer of protection to your code.It ensures that important values, methods, or classes remain unchanged and secure from accidental modification.
Use final when you want immutability, security, or code stability in your Java applications.
Project Tip:
In your Banking App, use final for:
-
Account types (final class SavingsAccount)
-
Interest rates (final double RATE)
-
Audit logging (final void log())
-
Transaction records (final class Transaction)
You now fully master the final keyword with a secure, real-world banking system!
Keep building — happy coding! ![]()