Spice up your Java using Project Lombok
Lombok is used to reduce boilerplate code for model/data objects, e.g., it can generate getters and setters for those objects automatically by using Lombok annotations.

Java is a great language and I like it, but for some common tasks in our code it becomes too verbose. You have to write a lot of code just to achieve a small task which you could achieve the same task with fewer lines of code in other programming/scripting languages.
You might have encountered the situation where you could write getters, setters, constructors, toString methods for each model/data class which increases your development process. If you want to add few more fields to the same class (POJO) you have to again generate getters and setters for it. Even though an IDE could generate getters and setters for you, still the getter/setters lie around your class files and you may have to manage the code. To avoid this repetitive process, Project Lombok comes to the rescue to make us more productive. The offical lombok website can be found here: https://projectlombok.org/
Without Lombok:
public class User {
private Integer id;
private String username;
private String email;
private String password;
// Getters, Setters and Constructors - approx 40 lines of code for above four fields
}
This is small class with only four fields, but we had to write around 40 lines of code extra for getters setters and constructors. Most of the code is to write only getters and setters. If it is around 10-15 classes it is still fine, but what if we have hundred similar data classes in our project? The number of lines of code to be written are very big.
Writing getters, setters, constructors, toString, hashCode methods are very common in every Java project. To handle this common situation we have Project Lombok. By using simple set of annotations, it will reduce a good amount of boilerplate code in data classes.
How it works?
Project Lombok works like magic from the outside. It provides annotations that you can use in your classes. It then plugs into build process and automatically generates Java bytecode into .class files with the number of annotations provided in your code.
With Lombok:
Let's make the above User class free from getter/setters or boilerplate code by using Lombok's annotations:
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class User {
private Integer id;
private String username;
private String email;
private String password;
}
That's it. The annotations @Getter
, @Setter
will automatically generate the default getter and setters for the fields in your class. Normally, whenever you modify a field or add a new one, you will have to manage the corresponding getter/setters or add getter/setters for the new field respectively. With lombok you don't have to do that. In addition to it, it also increases the readability of the source code and saves space.
Installation:
Lombok is a sinlgle jar file which you can get from https://projectlombok.org/download. For the installation instructions, you can visit the official site https://projectlombok.org.
If you are using Maven, you can simply add the following dependency in the pom.xml file to include lombok:
<dependencies>
...
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
<scope>provided</scope>
</dependency>
....
</dependencies>
If you are using Gradle, add the following dependency in build.gradle file:
// https://mvnrepository.com/artifact/org.projectlombok/lombok
compileOnly group: 'org.projectlombok', name: 'lombok', version: '1.18.20'
To install it in IntelliJ, navigate to plugins section in settings and search for lombok and proceed for the installation.
Lombok Annotations:
All the Lombok annotations can be found here. Let's discuss the annotations provided by Lombok.
1) Getters/Setters and Constructors : It is a common practice to encapsulate the object fields via getters and setters. Lombok's @Getter
and @Setter
annotations are used to generate the default getter and setter methods for the instance variables of the class. These annotations can be applied at field level or at class level. If these annotations are applied at class level, getters and setters would be generated for all the non-static fields of the class.
Let's consider the above class to use as JPA entity and add Lombok's annotations to it:
import javax.persistence.Entity;
import lombok.Getter;
import lombok.Setter;
@Entity
@Getter // ----> 1
@Setter // ----> 2
public class User {
@Id
private Long id; // will be set when persisting
private String username;
private String email;
private String password;
public User(String username, String email, String password) {
this.username = username;
this.email = email;
this.password = password;
}
}
By adding @Getter, @Setter, we told Lombok to generate getters and setters for all the fields of the class.
The generated getters and setters will be public unless you explicitly specify an AccessLevel
. AccessLevels are PUBLIC
, PROTECTED
, PACKAGE
, and PRIVATE
. For example, if we want to set package or protected access to our id field, we could do like this:
@Id
@Setter(AccessLevel.PROTECTED)
private Long id;
2) Getter with lazy:
There are times in which some operations take a lot of CPU or memory to execute. This expensive operations needed to be saved for subsequent use. So, we need to retrieve this kind of data once and then cache it for in-memory reads within the application. To use this feature from Lombok, we need to create a private final
variable and initialize it with expression that is expensive to run. Now make the field annotated with @Getter(lazy = true)
. When this getter is called, the expression would be evaulated no more than once. The calculation need not be thread-safe, as lombok takes care of locking.
import lombok.Getter;
public class LazyGetterDemo {
@Getter(lazy = true)
private final int[] cached = expOp();
private int[] expOp() {
int[] result = new int[1000000];
for (int i = 0; i < result.length; i++) {
result[i] = Math.sqrt(i);
}
retun result;
}
}
3) Non Null:
@NonNull
annotation is used to generate null checks for the annotated fields. When used on an instance variable, all the setter methods, or constructors generated by lombok will contain a null check for that instance variable. If this annotation is used on method parameter or constructor, a null check for that parameter will be inserted inside the method or constructor.
public class User {
@Getter
@Setter
@NonNull
private String username;
}
3) To String:
@ToString
will generate a toString() method which includes all class attributes. By default, it prints the class name along with attribute values in order separated by commas.
@ToString
public class User {
private String firstname;
private String lastname;
}
/* equivalent to
* @Override
* public String toString() {
* return "User(" + firstname + "," + lastname + ")";
* }
*/
If you want to include attribute/field names in the toString()
method, use @ToString(includeFieldNames = true)
. By default, all the non-static fields will be printed. If you want to skip some fields, use @ToString(exclude = "fieldName")
and for multiple fields use @ToString(exclude = {"field1, "field2"})
. You can also specify which fields you want to be included in toString() method using @ToString(of = {"field1", "field2"})
.
@ToString(includeFieldNames = true, exclude = {"id", "lastname"})
public class User {
private Integer id;
private String firstname;
private String lastname;
private String username;
private String email;
}
To include the output of super class implementation of toString(), you can use @ToString(callSuper = true)
.
4) Equals and Hash code:
You can annotate any class definition with @EqualsAndHashCode
to let Lombok generate equals and hash code implementation methods. By default, it will use non-static and transient fields. To exclude more fields, use exclude
parameter or to include more fields use of
parameter.
@EqualsAndHashCode(exclude = {"firstname", "lastname"})
public class User {
private Integer id;
private String firstname;
private String lastname;
private String username;
private String email;
}
5) NoArgsConstructor, RequiredArgsConstructor and AllArgsConstructor:
@NoArgsConstructor
will generate a constructor with no parameters. If this is not possible, because of final fields which must be initialized, compiler will throw an error. If @NoArgsConstructor(fore = true)
is used, then all the final fields will be initialized with 0
/false
/null
.
@NoArgsConstructor(force = true)
public class User {
private final Integer id = 0;
private String username;
}
@RequiredArgsConstructor
generates a constructor for all final fields and @NonNull
fields in the class. Adding @NonNull
to fields makes constructor check for nullability and throw NullPointerExceptions accordingly. This would also happen if the fields were non-final and we added @Setter for them.
@RequiredArgsConstructor
public class User {
private final Integer id = 0;
@NonNull
private String username = "guest";
private String name;
private final String email;
@NonNull
private String country;
}
In the above class, id, username, and name are not included in the generated @RequiredArgsConstructor
because id, username are already initialized and name is neither final nor annoated with @NonNull
.
@AllArgsConstructor
generates a constructor with all the fields in your class. Also, null-checks are added for fields marked with @NonNull
.
6) Data:
@Data
is shortcut annotations for @Getter
, @Setter
, @ToString
, @EqualsAndHashCode
and @RequiredArgsConstrucor
together. In other words, @Data
generates all the boilerplate that is normally associated with simple POJOs (Plain Old Java Objects) and beans:
There are also other useful annotations in Lombok library. Have a look at their features page.