Lombok and Java - Simplifying Boilerplate Code with Examples

By keylearn

Project Lombok is a Java library that helps reduce boilerplate code, making Java development faster and cleaner. It provides annotations that automatically generate common methods like getters, setters, constructors, toString(), equals(), hashCode() , logging at compile time.

Lombok integrates seamlessly with most Java IDEs, including IntelliJ IDEA, Eclipse, and VS Code, through plugins that enable real-time annotation processing.

Why Use Lombok? Java is known for its verbosity, requiring developers to write extensive code for simple tasks like encapsulation and object comparison. Lombok eliminates this redundant code while keeping Java’s static typing and performance intact.

Key benefits of Lombok:

Reduces boilerplate code Improves code readability and maintainability Enhances productivity Works seamlessly with existing Java projects How to Add Lombok to a Java Project Lombok can be easily added to a Maven or Gradle project.

Using Maven Add the following dependency in your pom.xml file:

org.projectlombok lombok 1.18.30 provided

The provided means that Lombok is required during compilation but not included in the final build (such as JAR or WAR files). This is because Lombok is a compile-time tool that generates bytecode but does not need to be present at runtime.

Using Gradle Add the dependency in your build.gradle file:

dependencies { compileOnly ‘org.projectlombok:lombok:1.18.30’ annotationProcessor ‘org.projectlombok:lombok:1.18.30’ } Common Lombok Annotations with Examples

  1. @Getter and @Setter

Generates getter and setter methods automatically.

import lombok.Getter; import lombok.Setter;

public class User { @Getter @Setter private String name; @Getter @Setter private int age; } Equivalent Java code without Lombok:

public class User { private String name; private int age;

public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; } } 2. @NoArgsConstructor, @AllArgsConstructor, and @RequiredArgsConstructor    These annotations generate constructors.

import lombok.AllArgsConstructor; import lombok.NoArgsConstructor; import lombok.RequiredArgsConstructor; import lombok.Getter; import lombok.Setter;

@NoArgsConstructor // Generates a no-arg constructor @AllArgsConstructor // Generates a constructor with all fields @RequiredArgsConstructor // Generates a constructor with final fields @Getter @Setter public class Employee { private String name; private int age; }

  1. @ToString Automatically generates a toString() method.

import lombok.ToString;

@ToString public class Product { private String name; private double price; }

  1. @EqualsAndHashCode Generates equals() and hashCode() methods.

import lombok.EqualsAndHashCode;

@EqualsAndHashCode public class Book { private String title; private String author; }

  1. @Data A combination of @Getter, @Setter, @ToString, @EqualsAndHashCode, and @RequiredArgsConstructor.

import lombok.Data;

@Data public class Car { private String model; private int year; }

  1. @Builder Used for implementing the Builder pattern.

import lombok.Builder; import lombok.ToString;

@Builder @ToString public class Person { private String firstName; private String lastName; private int age; } public class Main { public static void main(String[] args) { Person person = Person.builder() .firstName(“John”) .lastName(“Doe”) .age(30) .build(); System.out.println(person); } }

  1. @NonNull Ensures that a field or method parameter cannot be null.

import lombok.NonNull; import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor public class Customer { @NonNull private String name; private int age; } This will generate a constructor that includes a null check for name, throwing a NullPointerException if a null value is provided.

  1. Lazy Loading Lombok provides the @Getter(lazy = true) annotation to implement lazy loading.

import lombok.Getter;

public class LazyExample {

@Getter(lazy = true)
private final String expensiveData = loadExpensiveData();

private String loadExpensiveData() {
    System.out.println("Loading expensive data...");
    return "Expensive Data Loaded";
}
public static void main(String[] args) {
    LazyExample example = new LazyExample();
    System.out.println("Object created, but data not loaded yet.");
    // Data will be loaded only when accessed for the first time
    System.out.println(example.getExpensiveData());
} } Improves Performance — Reduces memory usage by only loading data when needed. Faster Startup Time — Delays the loading of heavy resources.
  1. Access Level Lombok’s @Setter annotation is used to automatically generate setter methods for fields in a Java class. However, sometimes you may want to restrict the access level of these setters.

import lombok.AccessLevel; import lombok.Getter; import lombok.Setter;

public class User {

@Getter @Setter // Public getter and setter
private String name;
@Getter
@Setter(AccessLevel.PROTECTED) // Generates a protected setter
private int age; } Generated Setter Methods: The above code is equivalent to:

public class User { private String name; private int age;

public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
protected void setAge(int age) { this.age = age; } // Protected setter } Here, setAge(int age) is protected, meaning it can only be accessed within: The same class, Subclasses (child classes), The same package (for package-private access).

Example of Different Access Levels:

@Setter(AccessLevel.PRIVATE) // Private setter @Setter(AccessLevel.PROTECTED) // Protected setter @Setter(AccessLevel.PACKAGE) // Package-private setter

  1. Immutable copies The @With annotation in Lombok is used to create immutable copies of an object with a modified value for a specific field. Instead of modifying the original object, it returns a new instance with the updated value, leaving the original unchanged.

Why Use @With? Immutability — Ensures objects remain unchanged while allowing modifications through new instances. Fluent API Style — Enables chaining of method calls. Thread Safety — Useful in multi-threaded applications where immutable objects are preferred. import lombok.With; import lombok.AllArgsConstructor; import lombok.ToString;

@AllArgsConstructor // Required for @With to work @ToString public class Car { @With private final String model; @With private final int year; }

public class Main { public static void main(String[] args) { Car car1 = new Car(“Tesla Model 3”, 2022); System.out.println(car1); // Car(model=Tesla Model 3, year=2022)

    Car car2 = car1.withYear(2025); // Creates a new instance
    System.out.println(car2); // Car(model=Tesla Model 3, year=2025)
} } Conclusion Lombok significantly reduces the amount of boilerplate code in Java projects, leading to more readable and maintainable code. By using Lombok annotations, developers can focus more on business logic rather than writing repetitive methods.

However, it’s important to ensure that the development team understands Lombok and its generated code. Also, some tools and frameworks might not work well with Lombok-generated methods, so testing compatibility is essential.

If you haven’t used Lombok yet, give it a try and experience the benefits firsthand!

Share: