If you’re already using Lombok in a project, you’re likely leveraging its concise and boilerplate-reducing features. Among these features is Lombok’s val, a powerful tool that introduces local variable type inference into Java. Even though Java’s own var keyword (introduced in Java 10) provides similar functionality, there may still be situations in which Lombok’s val feels like an appealing option. However, before adopting val broadly, it is essential to evaluate what it is, how it works, and the risks and advantages associated with it—especially given the ongoing evolution of Java.
What is Lombok’s val?#
Lombok’s val is a real generic type provided by the Lombok library. You can declare local variables using val as their type, and Lombok’s annotation processor recognizes this special type during compilation. The processor then infers the actual type from the initializer expression and replaces the val type with the concrete type, while also making the variable final.
For instance:
import lombok.val;
// ...
val myList = new ArrayList<String>();Note that val must be imported ( import lombok.val;) for the code to compile; using it as lombok.val whould possible, but quite ugly.
Here, you’re declaring a variable of type val, which is valid Java syntax. Lombok’s processor will infer that myList is of type ArrayList<String>, make the variable final, and transform the code to:
final ArrayList<String> myList = new ArrayList<>();How Does Lombok’s val Work Under the Hood?#
Lombok uses Java’s annotation processing mechanism to detect the use of the val type in variable declarations. Specifically, Lombok:
Scans your code for
valtype declarations.Analyzes the initializer expression to determine its actual type.
Rewrites the code in the Abstract Syntax Tree (AST) before the compiler moves to the type checking phase, replacing
valwith the inferred concrete type and adding thefinalmodifier.
For example, when you write:
val x = 42;Lombok transforms this into:
final int x = 42;This transformation occurs between Java’s parsing phase (which validates the syntax) and its type checking phase (which ensures type compatibility). By the time the type checker analyzes the code, Lombok has already replaced the val type with the appropriate final type. The fact that val is a real, importable type means this transformation is completely compatible with Java’s standard compilation process.
Advantages of Lombok’s val#
Given that Lombok is already part of your project, the additional benefits of using val include:
Cleaner and More Readable Code:
Eliminates repetitive boilerplate such as explicitly specifying types that are already clear from the initializer.
Improves focus on the logic rather than the types.
val result = someMethod(); // Cleaner than explicitly declaring the return typeCompile-Time Safety:
- Unlike dynamic languages, Lombok’s
valensures static type checking. If the initializer’s type is incompatible, the compiler will produce an error.
- Unlike dynamic languages, Lombok’s
Immutability Enforcement:
- All
valvariables are automaticallyfinal, reducing accidental reassignment and promoting immutability practices.
- All
Consistency Across All Java Versions:
- You can use
valfor type inference even if your project is running on a Java version prior to Java 10, wherevarwasn’t available.
- You can use
Part of the Lombok Ecosystem:
- If your project is already relying on Lombok for features like
@Data,@Builder, or@Getter,valintegrates seamlessly with no additional dependencies.
- If your project is already relying on Lombok for features like
Disadvantages of Lombok’s val#
However, there are some trade-offs to consider:
Redundancy with
var(Java 10 or Later):- Since Java natively supports type inference with the
varkeyword, using Lombok’svalin modern projects may seem redundant and unnecessary.
// Native Java solution (Java 10+) var myList = new ArrayList<String>();- Since Java natively supports type inference with the
Less Flexible Than
varin Non-Final Scenarios:- Unlike
var, Lombok’svalenforces immutability by making variablesfinal. For mutable variables, you need to avoidval.
- Unlike
Reliance on Lombok’s Annotation Processing:
- Lombok’s code manipulation creates a dependency on its annotation processor. While
valis a real type and thus valid Java, any changes to how annotation processing works in Java (e.g., compiler internals) could potentially affect how Lombok detects and transformsvaldeclarations.
- Lombok’s code manipulation creates a dependency on its annotation processor. While
Future Compatibility Risks:
- Lombok relies on undocumented/internal APIs of the Java compiler (like
com.sun.tools.javac) and integrates deeply with the compilation process. This reliance means that changes in Java’s compiler infrastructure may rendervalincompatible without updates to Lombok.
- Lombok relies on undocumented/internal APIs of the Java compiler (like
Learning Curve:
- Developers unfamiliar with Lombok may find
valcounterintuitive or confusing, particularly if they are already accustomed to Java’svar.
- Developers unfamiliar with Lombok may find
Risks for Future Java Versions#
1. Annotation Processing Policy Changes#
Future versions of Java could modify how annotation processing works, making Lombok’s AST manipulations more difficult or outright impossible. Discussions around stricter controls on annotation processing have already surfaced in Java’s community.
2. Conflict with Native Features#
Java already offers var for type inference natively. Introducing further advancements in type inference, or changes to type inference mechanics (e.g., with Project Valhalla), might conflict with Lombok’s val.
3. Dependency on Java Internals#
Lombok depends on internal compiler APIs like com.sun.tools.javac, which are neither stable nor guaranteed to be supported across major Java versions. Breaking changes could require significant updates to Lombok or make it incompatible until fixed.
4. Inconsistent Support for New Java Versions#
Historically, Lombok has been slow to support new JDK releases, often requiring updates to remain compatible. This lag might impose delays on projects relying on val when upgrading the Java version.
Should You Use val?#
Here’s a balanced perspective:
When to Use#
If you are already using Lombok widely and the Java version in your project is below Java 10,
valis a natural choice for type inference.Use it in scenarios where variables will remain immutable (
final).
When to Avoid#
If you are using Java 10 or above, prefer the native
varkeyword for type inference.In mutable contexts, avoid
valsince it enforcesfinal.
Practical Recommendation#
Short-Term (2-5 Years): Lombok’s
valis stable and safe to use today in projects already relying on Lombok. However, weigh its usage carefully againstvarin Java 10+ projects.Long-Term (Beyond 5 Years): Consider migrating towards Java-native features like
varfor future-proofing. As Java evolves, Lombok’s reliance on annotation processing and compiler internals introduces increasing risk.
Conclusion#
Lombok’s val remains a compelling choice for modern Java projects—provided you’re already using Lombok and understand its mechanics. It simplifies local variable declarations, promotes immutability, and remains compatible with older Java versions. However, with the rise of native features like var and ongoing changes in the Java platform, the long-term stability of val is not guaranteed. For newly written code, utilizing var is generally more sustainable over time.
By carefully considering your project’s Java version, team familiarity, and potential risks, you can decide whether val deserves a permanent place in your codebase!
