Java is a verbose programming language when compared to Python, Kotlin. For instance, to write a POJO we might have to add accessors, mutators explicitly. This is good if the class has less number of fields. Otherwise, adding them is simply boring, unless if someone wants to test their typing speed.

Lombok is a library that takes the responsibility of writing boilerplate code for us thereby reducing the verbosity, and keeps the code clean and concise.

During compile time, lombok annotations adds required boilerplate code and generates bytecode. To see the effective bytecode which contains the auto-generated code by lombok, we can decompile the class file. This decompiled version of code is AKA delomboked code.

We can delombok the code to see the lombok auto-generated boilerplate code

java -jar lombok.jar delombok -p Book.java

Here are the basic lombok annotations and their corresponding delombok version

  1. @NoArgsConstructor:

    • Lombok

        import lombok.NoArgsConstructor;
      
        @NoArgsConstructor
        class Book {
          String title;
          String author;
        }
      
    • Delombok

        class Book {
          String title;
          String author;
                
          public Book() {}
        }
      
  2. @AllArgsConstructor:

    • Lombok

        import lombok.AllArgsConstructor;
      
        @AllArgsConstructor
        class Book {
          String title;
          String author;
        }
      
    • Delombok

        public class Book {
          String title;
          String author;
                
          public Book(final String title, final String author) {
            this.title = title;
            this.author = author;
          }
        }
      
  3. @RequiredArgsConstructor:

    • Lombok

        import lombok.RequiredArgsConstructor;
      
        @RequiredArgsConstructor
        public class Book {
          final String title;
          String author;
        }
      
    • Delombok

        public class Book {
          final String title;
          String author;
      
          public Book(final String title) {
            this.title = title;
          }
        }
      
    • Note: When there are no final fields then the @RequiredArgsConstructor creates a default constructor i.e., works like @NoArgsConstructor

  4. @Getter

    • Lombok

        import lombok.Getter;
      
        @Getter
        public class Book {
          String title;
          String author;
        }
      
    • Delombok

      public class Book {
        String title;
        String author;
      
        public String getTitle() {
          return this.title;
        }
              
        public String getAuthor() {
          return this.author;
        }
      }
      
  5. @Setter

    • Lombok

      import lombok.Setter;
      
      @Setter
      public class Book {
        String title;
        String author;
      }
      
    • Delombok

      public class Book {
        String title;
        String author;
      
        public void setTitle(String title) {
          this.title = title;
        }
      
        public void setAuthor(String author) {
          this.author = author;
        }
      }
      
  6. @ToString:

    • Lombok

      import lombok.ToString;
      
      @ToString
      class Book {
        String title;
        String author;
      }
      
    • Delombok

      public class Book {
        String title;
        String author;
              
        @Override
        public String toString() {
          return "Book(title=" + this.title + ", author=" + this.author + ")";
        }
      }
      
  7. @EqualsAndHashCode:

    • Lombok

        import lombok.EqualsAndHashCode;
      
        @EqualsAndHashCode
        public class Book {
          String title;
          String author;
        }
      
    • Delombok

        public class Book {
          String title;
          String author;
      
          @Override
          public boolean equals(final java.lang.Object o) {
            if (o == this) return true;
            if (!(o instanceof Book)) return false;
            final Book other = (Book) o;
            if (!other.canEqual((java.lang.Object) this)) return false;
            final java.lang.Object this$title = this.title;
            final java.lang.Object other$title = other.title;
            if (this$title == null ? other$title != null : !this$title.equals(other$title)) return false;
            final java.lang.Object this$author = this.author;
            final java.lang.Object other$author = other.author;
            if (this$author == null ? other$author != null : !this$author.equals(other$author)) return false;
            return true;
          }
      
          protected boolean canEqual(final java.lang.Object other) {
           return other instanceof Book;
          }
      
          @Override
          public int hashCode() {
            final int PRIME = 59;
            int result = 1;
            final java.lang.Object $title = this.title;
            result = result * PRIME + ($title == null ? 43 : $title.hashCode());
            final java.lang.Object $author = this.author;
            result = result * PRIME + ($author == null ? 43 : $author.hashCode());
            return result;
          }
        }
      
  8. @Data: Bundles all the features of @RequiredArgsConstructor, @Getter, @Setter, @EqualsAndHashCode, and @ToString together

    • Lombok

      • import lombok.Data;
        
        @Data
        public class Book {
          final String id;
          String title;
          String author;
        }
        
    • Delombok

        public class Book {
          final String id;
          String title;
          String author;
      
          public Book(final String id) {
           this.id = id;
          }
      
          public String getId() {
            return this.id;
          }
      
          public String getTitle() {
            return this.title;
          }
      
          public String getAuthor() {
            return this.author;
          }
      
          public void setTitle(final String title) {
            this.title = title;
          }
      
          public void setAuthor(final String author) {
            this.author = author;
          }
      
          @java.lang.Override
          public boolean equals(final java.lang.Object o) {
            if (o == this) return true;
            if (!(o instanceof Book)) return false;
            final Book other = (Book) o;
            if (!other.canEqual((java.lang.Object) this)) return false;
            final java.lang.Object this$id = this.getId();
            final java.lang.Object other$id = other.getId();
            if (this$id == null ? other$id != null : !this$id.equals(other$id)) return false;
            final java.lang.Object this$title = this.getTitle();
            final java.lang.Object other$title = other.getTitle();
            if (this$title == null ? other$title != null : !this$title.equals(other$title)) return false;
            final java.lang.Object this$author = this.getAuthor();
            final java.lang.Object other$author = other.getAuthor();
            if (this$author == null ? other$author != null : !this$author.equals(other$author)) return false;
            return true;
          }
      
          protected boolean canEqual(final java.lang.Object other) {
            return other instanceof Book;
          }
      
          @java.lang.Override
          public int hashCode() {
            final int PRIME = 59;
            int result = 1;
            final java.lang.Object $id = this.getId();
            result = result * PRIME + ($id == null ? 43 : $id.hashCode());
            final java.lang.Object $title = this.getTitle();
            result = result * PRIME + ($title == null ? 43 : $title.hashCode());
            final java.lang.Object $author = this.getAuthor();
            result = result * PRIME + ($author == null ? 43 : $author.hashCode());
            return result;
          }
      
          @java.lang.Override
          public java.lang.String toString() {
            return "Book(id=" + this.getId() + ", title=" + this.getTitle() + ", author=" + this.getAuthor() + ")";
          }
                
        }    
      
  9. @Builder

    • Lombok

      import lombok.Builder;
      
      @Builder
      public class Book {
        String title;
        String author;
      }
      
    • Delombok

      public class Book {
        String title;
        String author;
      
        Book(final String title, final String author) {
          this.title = title;
          this.author = author;
        }
      
        public static class BookBuilder {
          private String title;
          private String author;
      
          BookBuilder() {}
      
          /**
          * @return {@code this}.
          */
          public Book.BookBuilder title(final String title) {
            this.title = title;
            return this;
          }
      
          /**
          * @return {@code this}.
          */
          public Book.BookBuilder author(final String author) {
            this.author = author;
            return this;
          }
      
          public Book build() {
            return new Book(this.title, this.author);
          }
      
          @java.lang.Override
          public java.lang.String toString() {
            return "Book.BookBuilder(title=" + this.title + ", author=" + this.author + ")";
          }
        }
      
        public static Book.BookBuilder builder() {
          return new Book.BookBuilder();
        }
      }
      
      

Lombok provides other annotations besides the aforementioned. Usage of annotation processors like Lombok is a developer’s preference. Excessive usage of these annotations makes code unreadable as it does a lot of magic under the hood through auto-generated code.

In summary

  • @NoArgsConstructor - Creates a default constructor
  • @RequiredArgsConstructor - Creates constructor with final fields as params, otherwise if a class has no final field at all, then it behaves like @NoArgsConstructor
  • @Data- Combination of @RequiredArgsConstructor + @Setter + @Getter + @EqualsAndHashCode + @ToString
  • @AllArgsContructor - Creates constructor with all fields in a class, whether they are final or not.
  • @Builder - Creates @AllArgsConstructor + builder pattern

Bad-combinations

  • @Builder + @NoArgsConstructor = Results in compilation error as they are contradicting
  • @AllArgsContructor(With final fields) + @NoArgsConstructor = results in compilation issue as final field has to be initialized

References:

  1. Project Lombok