final in Java
finalis a keyword in Java.finalcan be applied to variable, method, and class.In simple English
finalin 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
-
finalstatic 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
Xin static block or inline. Otherwise, it saysThe blank final field X may not have been initialized
-
-
finalinstance 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
xin instance block or in constructor. Otherwise, it saysThe blank final field x may not have been initialized
-
-
finallocal variable-
class Demo { void m1() { final int x; System.out.println("x = " + x); // Compiler error at this line } } - Compiler forces to initialize this var
xlocal 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
finalmethods 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
finalclass 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.Stringonce 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
finalto 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 likeEmployeetype, the onus is onEmployeeclass creator to properly make its state as immutable. Read official Javadoc on Java16 Records
-