final in Java
final
is a keyword in Java.final
can be applied to variable, method, and class.In simple English
final
in java means, once a variable is assigned a value, it cannot be reassigned with another value.-
Note that final for primitives makes them immutable and stateless. However, for wrappers, VOs, DTOs, and user-defined objects that have state, they are still mutable(Unless otherwise they are made immutable explicitly), and final has no impact on them, except that they cannot be reassigned.
-
Example:
import lombok.Data; @Data @AllArgsConstructor class Employee { private String name; private String email; } public class FinalDemo { Employee getEmployee() { return new Employee("srk","srk@loading.com"); } public static void main(String[] args) { FinalDemo fd = new FinalDemo(); final Employee employee = fd.getEmployee(); // Changing the state employee.setName("srk-real"); employee.setEmail("srk@outlook.com"); // employee = new Employee(); // Compiler Error: // The final local variable employee cannot be assigned. // It must be blank and not using a compound assignment } }
-
final
variable
-
final
static variable - A.K.A. CONSTANT in Java.-
class Demo { final static int X = 10; }
-
Or
class Demo { final static int X; static { X = 10; } }
- Compiler forces to initialize this var
X
in static block or inline. Otherwise, it saysThe blank final field X may not have been initialized
-
-
final
instance variable-
class Demo { final int x; { x = 10; } }
-
Or
class Demo { final int x; Demo(int x) { this.x = x; } }
- Compiler forces to initialize this var
x
in instance block or in constructor. Otherwise, it saysThe blank final field x may not have been initialized
-
-
final
local variable-
class Demo { void m1() { final int x; System.out.println("x = " + x); // Compiler error at this line } }
- Compiler forces to initialize this var
x
local variable. Otherwise, it saysThe local variable x may not have been initialized
-
Corrected code
-
class Demo { void m1() { final int x = 10; System.out.println("x = " + x); } }
-
-
final
method
final
methods can be overloaded, but cannot be overridden-
Example
class A { final void m1() { System.out.println("In void m1()"); } final void m1(String x) { System.out.println("In void m1(String x)"); } } class B extends A { void m1(String x) {} // Compiler error: Cannot override the final method from A }
-
final
class
final
class cannot be inherited.-
Example1
final class A {} class B extends A {} // Compiler error: The type B cannot subclass the final class A
-
Example2:
class A {} final class B extends A {} class C extends B {} // Compiler error: The type C cannot subclass the final class B
-
final
as method argument
-
Example:
class Demo { void m1(final int x) { x = 35; // Compiler error: The final local variable x cannot be assigned } }
Immutable Data Structure
- Immutable data structure is a data structure whose state cannot be modified after it is created.
- Benefits: Thread safety can be easily achieved without synchronization or locks as immutable data structure is inherently stateless.
- Best known example in Java is
java.lang.String
once assigned with a value cannot be changed and any new assignment will create a new object.-
Example:
String x = "hello"; // create a String in constant pool x += "world"; // creates a new String in constant pool
-
- Other examples:
-
List<String> fruits = List.of("apple", "grape"); // Java9 Syntax
-
List<String> fruits = new ArrayList<>(); // Pre-Java8 Syntax fruits.add("apple"); fruits.add("grape"); java.util.Collections.unmodifiableList(fruits);
- Note that in both the above examples, the returned list is immutable, any attempt to add or remove elements from the list results in
java.lang.UnsupportedOperationException
-
-
Immutable Class Example
final class Employee { private final String name; private final String email; public Employee(String name, String email) { this.name = name; this.email = email; } // NO mutators to prevent state change // Can have accessors to expose readonly view }
-
Here class is
final
to prevent inheritance and no mutators to restrict the state change, and all fields are final to ensure that the state is defined during the creation of the object and change in state requires create of new object. -
Alternatively, we can use Java records which are introduced in
Java16
. But it is shallowly immutable meaning works with primitives, but if it has fields likeEmployee
type, the onus is onEmployee
class creator to properly make its state as immutable. Read official Javadoc on Java16 Records
-