I have been a fan of the Scala programming language for a while. There are many language constructs built in to Scala where a good programmer will appreciate them. When you start writing Scala code, one thing you will certainly realize is that your code size starts to shrink. With Scala, your effort is mainly focused on the implementation tasks whereas in Java there are more ceremonial tasks to be done, and that extra work is hard to get away from. Scala and Java compile down to the same bytecode that can be run on a Java Virtual Machine and they are generally interoperable. Using Java classes in Scala is straightforward, but using Scala classes in Java has limitations because Java does not support all the Scala features.
The purpose of this article is to compare Scala case classes with the Lombok annotated Java classes. Lombok reduces a lot of boilerplate code from Java resulting in cleaner code.
Scala: Case Classes
One of the many nice features in Scala is “Case Classes”. Case classes are a special type of classes, which make their properties immutable, and can be used in pattern matching. You will also get
equals and accessor/mutator methods and constructors for free. Scala will also generate companion objects for case classes to add more functionality to the class (we are going skip that part in this article).
Lombok is a Java library that can be used to reduce the boilerplate code from Java classes. It can generate
equals and accessor/mutator methods and constructors at compile time. Simply by adding @Data annotation into a Java class, you can leverage all the aforementioned features. There are additional annotations that can be used to control the code generation more granularly. Lombok is also capable of handling resource clean-ups, synchronizing code blocks, etc.
Let’s Do Some Coding
Creating a case class in Scala requires one line of code (Code Block 1: line 3). Let’s create a Scala class called
ScalaFoo and add a string field and an integer field.
Code Block 1: Scala source code
After compiling the class, we can use the javap tool to decompile the bytecode. The decompiled code will be in the Java format.
Code Block 2: Decompiled code
The decompiled code shows the auto-generated
equals methods (Code Block 2: line 16, 17, 18), constructor (Code Block 2: line 19) and accessor methods (Code Block 2: line 6, 7). Notice that, in Scala, the accessor method name and the property name are the same. There are more auto-generated methods to support additional Scala features. In this particular case, when I was implementing this model object, I was mainly focusing on the class name, variable names and variable types while Scala did the rest of the work for me.
Now, let’s create a Java class called
LombokFoo and add a mutable string field and an immutable (final) integer field. Add the
@Data annotation, compile the source code and decompile the bytecode.
Code Block 3: Java source code
Once again let’s decompile the bytecode with javap tool.
Code Block 4: Decompiled code
The decompiled code shows the auto-generated
toString methods (Code Block 4: line 8, 10, 11), constructor (Code Block 4: line 4) and accessor/mutator methods (Code Block 4: line 5, 6, 7). Similar to Scala, I only had to focus on the names and types while Lombok did the ceremonial work for me.
(Note: In both Scala and Lombok generated code, we can see a
canEqual method. This article is not intended to discuss that feature, more details can be found in Lombok documentation and in this paper: “How to Write an Equality Method in Java”.)
As we can see, both Scala and Lombok will reduce the code size and the code generation behaves similarly. In the book “Programming in Scala”, Martin Odersky claims that the code reduction in number of lines in Scala can range from a factor of two to ten compared to Java. I am sure we can achieve a similar amount of code reduction for domain object classes in Java with Lombok compared to plain-old Java.
Why This is Important
- Less code generally means fewer bugs. Fewer bugs mean higher quality code and increased productivity.
- Reducing boilerplate code gives more time to work on the design, allowing you to design more extensible and reusable code.
- Programming should be targeted towards solving problems. We can be more productive if we are solving business-related problems rather than solving self-inflicted problems caused by the programming languages and frameworks.
- Do more with less!