Every year, we can hear about new tools that improve programming. They make the code shorter, more readable and easier to maintain. Today, I’m going to describe Project Lombok, which is a Java library mainly used for replacing traditional getters, setters and other instances of boilerplate code with single annotations.
To start using Lombok, we need to add maven dependency to pom file.
While I was writing this article, the newest version was: 188.8.131.52. I will use Intellij IDEA 2017.2.5 for some examples below.
Next, we need to install Lombok Plugin in the IDE.
And the last step is to enable annotation processing in the IDE. In order to do that, go to Settings → Build, Execution, Deployment → Compiler → Annotation Processors. Now we check “Enable annotation processing” and we are ready to use Lombok in our Java code.
Getters, setters and constructors
Let’s create a simple POJO class Person with 3 fields: name, address, and age. After adding getters, setters and constructor for all the parameters, it looks as follows:
Using the Lombok tool, the code for the Person class looks like this:
As we can see, the code looks much, much better and thanks to these 3 annotations the behavior of the Person class is the same.
It is also possible to perform lazy initialization for any field, which is useful if there are some complicated calculations that we want to calculate only once and, at the moment, we need it. For that, we have to make the field final and add @Getter(lazy=true). The value will be calculated once – the first time this getter is called.
For constructors, we can also use, depending on our needs, other annotations:
@RequiredArgsConstructor – which creates a constructor only for fields marked as final or with another Lombok’s annotation: @NonNull.
@NoArgsConstructor – which creates public and no arguments constructor.
Builder, which is a commonly used design pattern, enables us to initialize class in quite a convenient way. The thing is that its implementation isn’t so nice. Here we can see the implementation for our Person class:
Fortunately, Lombok helps us with that as well. All we need to do is add @Builder annotation on top of the class instead of the long builder’s implementation (as it was in the code above). Example:
Moreover, we can enable toBuilder option: @Builder(toBuilder=true) which allows us to set values to an instance of an object and keep the ones we set before in an easy way. For example, let’s imagine that we have an instance of class “Person” and we set its field name to Peter.
Then, we want to add other fields, so we can do it like this:
Now, the person object has the following attributes: age, country and name (25, Poland, Peter). It is very useful when we have many fields in the class and we set them in more than one method.
ToString and EqualsAndHashCode
Lombok has also annotations for toString, equals, and hashCode methods. Without them, we were forced to do it this way:
With Lombok, it’s just a few lines of code:
Option exclude = “id” means that we don’t want to use this field in specified methods.
Value and Data
There are useful annotations: @Value and @Data, which are a composition of other annotations. So @Value is shorthand for: @ToString, @EqualsAndHashCode, @AllArgsConstructor, @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE), @Getter, and @Data is shorthand for: @ToString, @EqualsAndHashCode, @Getter on all fields, @Setter on all non-final fields, and @RequiredArgsConstructor.
Lombok has implemented some variants for Logger fields. It’s not necessary anymore to put a private static final field for logger. Proper annotation at the top of the class will be enough. So we can use one of these annotations:
@CommonsLogCreates, @JBossLog, @Log, @Log4j, @Log4j2, @Slf4j, @XSlf4j:
instead of one of these long declarations:
private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(LogExample.class); private static final org.jboss.logging.Logger log = org.jboss.logging.Logger.getLogger(LogExample.class); private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(LogExample.class.getName()); private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(LogExample.class);
private static final org.apache.logging.log4j.Logger log = org.apache.logging.log4j.LogManager.getLogger(LogExample.class); private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LogExample.class); private static final org.slf4j.ext.XLogger log = org.slf4j.ext.XLoggerFactory.getXLogger(LogExample.class);
@Synchronised – avoids multiple threads using a method at the same time.
@Cleanup – putting this annotation on the resource field (e.g. InputStream, OutputStream) will perform method close() on it before the code execution path exits your current scope.
val, var – we can use them as types of local variable declarations instead of actually writing the type. The difference between these two declarations is that the first one will make the field final.
final String name = “Steve”;
is the same as:
val name = “Steve”;
String name = “Steve”;
is the same as:
var name = “Steve”;
And if you want to learn more about Project Lombok and its features, take a look at projectlombok.org.
Last but not least, it is worth mentioning how Lombok actually works. While building the project, all annotations which were used are replaced with actual implementations, so if we go to target directory, we can see that the code is much longer and looks differently than it was originally written. We can say that Lombok just creates a visual impression for us to present the code in a better way, but when a compiler starts to work, everything comes back to its actual form.
As we can see, the Lombok Project is a very handy tool which significantly reduces lines of code. In my opinion, it also makes a project much more readable and there is smaller possibility of making mistakes using these annotations. If we don’t like it, we can always use the delombok feature (Code → Refactor → Delombok) which will switch annotations for original implementations.