Skip to main content
A final variable creates a single-assignment binding that is initialized at runtime. Once a value is assigned to a final variable, the reference cannot be changed, enforcing immutability on the variable binding itself.

Syntax and Declaration

A variable is declared final by prepending the final keyword. Type annotation is optional; if omitted, the type is inferred from the assigned value.
// With explicit type annotation
final String protocol = 'https';

// With type inference
final port = 8080; // Inferred as int

Initialization Mechanics

Unlike const, which requires compile-time constants, final variables are evaluated and initialized at runtime. This allows the assignment of values that are calculated during program execution.
// Valid: Value determined at runtime
final DateTime startTimestamp = DateTime.now();
A final variable must be initialized exactly once. If the compiler cannot guarantee that the variable is initialized before it is used, it raises a static analysis error.

Reference Immutability vs. Object Mutability

The final keyword enforces immutability on the reference, not necessarily on the object being referenced.
  1. Immutable Reference: You cannot reassign the variable to a new object.
  2. Mutable State: If the referenced object is mutable (e.g., a List or a class with non-final fields), its internal state can still be modified.
final List<String> languages = ['Dart', 'Java'];

// Allowed: Modifying the internal state of the object
languages.add('Python'); 

// Error: Reassigning the variable to a new reference
// languages = ['Go', 'Rust']; // Compilation Error

Class Instance Variables

When a field within a class is declared final, it must be initialized before the constructor body executes. This can be achieved via:
  1. Inline initialization at the point of declaration.
  2. Initializing formal parameters.
  3. An initializer list.
class Configuration {
  final String apiKey;       // Must be set by constructor
  final int timeout = 3000;  // Inline initialization

  // Initialization via initializing formal parameter
  Configuration(this.apiKey);
}

Late Initialization

If a final variable cannot be initialized at declaration time but is guaranteed to be initialized before usage, the late modifier can be combined with final.
late final int computedValue;

void calculate() {
  computedValue = 42; // Allowed once
}

// Subsequent assignments to computedValue will throw a runtime exception.
Master Dart with Deep Grasping Methodology!Learn More