Lombok’s val – writing a cleaner Java … one value at a time.
Most people know and use Lombok’s @Data to generate boiler-plate code for Java. A few are aware of the lesser known feature call val -- for value. With val, you can write Java code without specifying local variable data type make the code much more pleasing to the eyes and faster to write.
Start with Why?
“Java is verbose” -- I am sure you have heard this and/or agreed with this statement. For one thing, Java requires you to specify the type of every place data can be stored like fields, parameters and local variables as well as where the type is referred such as the new statement or in generic. With Java 7 and 8, we can opt out some of these but still, they are required in so many places. The most notably ones are local variables. Let look at the following code.
list = loadData(database); String term = getSearchTerm(request); List filtedList = list.stream() .filter(onlyWith(term)) .collectors(toList()); …
See types? Are they really needed? Look closer, some of them can be derived from its surrounding. Languages like Scala and Kotlin has val keyword used to define local variable without specifying the type. Lombok’s val provides just that functionality to Java.
Let’s use it in the codeWith Lombok’s val, the above code can look like this…
… val list = loadData(database); val term = getSearchTerm(request); val filtedList = list.stream() .filter(onlyWith(term)) .collectors(toList()); …
This looks much cleaner. I really like that the variable names are now line up at the same column. The variable names are now like annotations of each line showing what each line is all about.
Not only that, not having to specify the type speeds things up quite a great deal. Especially, with Stream API. For example, when I change the result type of that data to string, I add the map(...) to the chain and done. I don’t need to change the type of filtedList.
… val filtedList = list.stream() .filter(onlyWith(term)) .map(Object::toString) .collect(toList()); …
Lombok’s val is translated at compile time to the type of the expression on the right and with val modifier. Another word, it will be replaced by the actual type and it can’t be modified. This means that it is used to defined value and not a variable -– that is it can’t be changed. Now, I can hear some people scream in horror … “Why? Oh Why? Do you the create a local variable and expect not the change its value?” (Yes, there are such persons). Sigh, if you like that, you can go your way. I like my code with one expression (or few) per line. It is diff (version control) and debug friendly and much easy to read but that is the discussion for another time.
We saw what val can do; Now let see what it can’t do. Well, for starter, it can only be used to replace local variable type. You can’t use with for something else like fields or parameters. Secondly, it can’t be used where the type was not cleared. One such place is lambda. To demonstrate, the following code is not valid.
… val action = ()->superHero.somethingAwesome(); …
val just have no idea what type this thing would be (even it obvious to you and me that it is a supplier of something awesome).
Another limitation have to do with the problem Gradle. Sometimes, code with val in a lambda results in compile error with done with Gradle, the same code pass normally with Eclipse. Fortunately, this does not happen often and the discrepancy is consistence meaning that once the code fail or pass in Gradle, it is always fail or pass so I normally just replace it with the expected types. Not idea but acceptable.
How to use?
Well, first of, you will need to add Lombok to your work space. Visit Lombok website to find instruction of how to do that.
Once you have that installed, you will need to import val into your source code to use it. If you get Lombok to work properly, your IDE should treat it like other types.
Some of my friends/co-workers despise the use of val. They say that it makes Java a dynamic or weak typed language. Some complains that they can’t see what types things are.
val does not make Java a dynamic or weak typed language. Since you cannot use val for parameter or field type – only for variables and you cannot reassign another values to val variables, the type of such variables are constant so Java with val is still a static and strong typed language.
The complains that with val we do not know what type things are is a fair complains. However, I didn’t find this to be problem much. Seeing name of the variables and the expression that generate the value, I can most of the time tell what sort data is it. The operations done to it should hint what type of object it is. Worse comes to worst, we can put the mouse over the variable name which, in most IDE, gives me exactly what type it is. And since the IDE know what type it is (as Lombok compile the code and IDE read the byte code not the source code), it can handle auto-completion normally. So, it is not a big problem.
All in all, it depends on your team if using val is acceptable. Because code is not only use to communicate with computer but even more so between humen.
If you think this is a small little thing, you are right but don’t be fool. Local variables are everywhere so the total effect of its use can be significant. Scanning your eyes in the code and see variable are line up so you can easily spot them incresing speed of looking thought it. Additionally, Without having to think about the exact type of your variable up front (as it is the first thing you type), you can focus on the logic. Final local variables are like documentations of steps in your code. Their values are in the descriptiveness of whatever held in them rather than what can be in them – like their non-final counterpart. By freeing your thought from the unnecessary detailed like types of constants where the complier can do it for you, you can focus more on other things like the meaning and the logic.