Introduction to Lombok

Preetham Gowda
4 min readAug 17, 2021

--

Overview

Lombok can greatly reduce the number of lines of boilerplate code that are either generated in the IDE or written by hand. It generates the code at compile time and helps keep code clean, concise and to the point. This results in reduced maintenance overhead, fewer bugs and more readable classes.

Developers usually write or generate the below mentioned boilerplate code in classes and these can be generated by Lombok using annotations

Boilerplate code in POJO

  1. No-arg constructor
  2. Getters
  3. Setters
  4. toString
  5. hashCode
  6. equals
  7. Parameterized constructor
  8. Builders

Usage of Lombok

Import the dependency in the pom.xml

<dependency> 
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<scope>provided</scope>
</dependency>

Class without Lombok

Constructors in a class without Lombok
getters, setters, toString, hashCode, equals methods in a class without Lombok

Class with Lombok

class with Lombok annotations

Notice how a simple class which had 75 lines of code is reduced to 16 lines. The reduction in the number of lines of code for a large class will be quite significant.

Useful annotations

Annotation: @Getter and @Setter

Description: provides getters and setters like the below code

public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}

Usage:

@Getter
@Setter
public class Person{
private String name;
}

Annotation: @ToString

Description: provides toString method like the below code

@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", address='" + address + '\'' +
", email='" + email + '\''
'}';
}

Usage:

@ToString
public class Person{
private String name;
private String address;
private String email;
private String password;
}

eg:

@ToString(of = {“name”, “email”}) → creates a toString() method with name and email fields

@ToString(exclude = {“password”}) → creates a toString() method with all the variables excluding password field

Annotation: @NoArgsConstructor

Description: provides no-arg constructor. Generates the below code

public Person() {
}

Usage:

@NoArgsConstructor
public class Person{
private String name;
}

eg:

@NoArgsConstructor(access = AccessLevel.PACKAGE) → for package level constructor

Annotation: @AllArgsConstructor

Description: provides parameterized constructor. Generates the below code

public Person(String name, String address, String email, String password) {
this.name = name;
this.address = address;
this.email = email;
this.password = password;
}

Usage:

@AllArgsConstructor
public class Person{
private String name;
private String address;
private String email;
private String password;
}

Annotation: @EqualsAndHashCode

Description: generates equals and hashCode methods.

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return Objects.equals(name, person.name) && Objects.equals(address, person.address) && Objects.equals(email, person.email) && Objects.equals(password, person.password);
}
@Override
public int hashCode() {
return Objects.hash(name, address, email, password);
}

Eg:

@EqualsAndHashCode(of = {“name”, “email”}) → creates a hashCode() and equals() method with name and email fields

@EqualsAndHashCode(exclude= {“address”}) → creates a hashCode() and equals() method using all variables excluding address

Usage:

@EqualsAndHashCode
public class Person{
private String name;
private String address;
private String email;
private String password;
}

Annotation: @RequiredArgsConstructor

Description: generates a constructor for all final fields that have not already been initialized.

public Person(String name) {
this.name = name;
}

Usage:

@RequiredArgsConstructor
public class Person{
private final String name;
}

Annotation: @Data

Description: combination of @Getter + @Setter + @ToString + @EqualsAndHashCode + @RequiredArgsConstructor

Usage:

@Data
public class Person{
private String name;
}

Annotation: @Builder

Description: allows us to use Builder Pattern to create new instances.

Usage:

@Builder
public class Person {
private String name;
private String address;
private String email;
private String password;
public void method(){
Person p = Person.builder().name("abc").email("abc@abc.com").address("xyz").password("abcd").build();
}

Annotation: @Slf4j

Description: provides the access to log instance in the class. Avoids using the below line

private static final Logger LOG = LoggerFactory.getLogger(Person.class);

Usage:

@Slf4j
public class Person {
private String name;
private String address;
private String email;
private String password;
public void method(){
log.debug("inside a method");
}

Annotation: @SneakyThrows

Description: We are forced to catch it or declare. It’ll wrap any checked exceptions subject to be thrown in our method into a unchecked one. No need to write the below code

public void method(){
try {
FileReader reader = new FileReader(new File("abc"));
} catch (FileNotFoundException e) {
//catch exception
throw new RuntimeException(e);
}
}

Usage:

@SneakyThrows
public void method(){
FileReader reader = new FileReader(new File("abc"));
}

Annotation: @Delegate

Description: No need to implement the interface methods in every class, we can delegate to already implemented class

Usage:

public class Person implements MyInterface{

@Delegate(types = {MyInterface.class})
private final MyInterfaceImpl myInterfaceImpl = new MyInterfaceImpl();

Annotation: @RequiredArgsConstructor(onConstructor = @__(@Autowired))

Description: Provides the constructor like the below code

public class PersonController {private final PersonService personService;
private final SomeService someService;
@Autowired
public PersonController(PersonService personService, SomeService someService) {
this.personService = personService;
this.someService = someService;
}

Usage:

@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class PersonController {
private final PersonService personService;
private final SomeService someService;
}

Delombok

To check what the Lombok has generated, you can use delombok which is provided with Lombok library in the IDE.

Conclusion

In this article, we covered most of the important annotations of Lombok library.

For more information about Lombok, refer Project Lombok

--

--