What did Lombok do for us

What is lombok

Lombok project is a Java library, tool library, which will automatically generate code in the editor or construction tool, so as to make your Java code more concise. Instead of generating get, set and other methods for each variable, it will also generate a fully functional Builder, which has automatically logged variables, and more

Common notes

  • @Setter
  • @Getter
  • @Builder
  • @RequiredArgsConstructor generates a construction method of this class, and nonparametric construction is prohibited
  • @ToString Override the toString() method of this class
  • @EqualsAndHashCode overrides the equals() and hashCode() methods of this class
  • @NoArgsConstructor
  • @AllArgsConstructor
  • @Data is equivalent to the sum of @ Setter @Getter @RequiredArgsConstructor @ToString @EqualsAndHashCode annotation
  • @Slf4j

Write a simple class and use this class to take a detailed look at what Lombok has done for us

package lombok;
public class UserData {
    private String name;
    private int age;
    private boolean good;
}

This class is very simple. There is no constructor or get set method in the code. Use javap tool to take a look

javap is jdk's own decompile tool. We don't care about the generated bytecode here, just look at the method

// javap UserData.class
Compiled from "UserData.java"
public class lombok.UserData {
  public lombok.UserData();
}

When JDK detects that there is no default constructor, it automatically generates a public parameterless default constructor

Use @ Getter

Add annotation @ Getter on class UserData

Compiled from "UserData.java"
public class lombok.UserData {
  public lombok.UserData();
  public java.lang.String getName();
  public int getAge();
  public boolean isGood();
}

After decompilation, you can see that the hump naming method is used to add the get variable method. You need to pay attention to the is method used by the boolean type

Use @ Setter

Compiled from "UserData.java"
public class lombok.UserData {
  public lombok.UserData();
  public void setName(java.lang.String);
  public void setAge(int);
  public void setGood(boolean);
}

Method of adding set variable after Decompilation

Use @ RequiredArgsConstructor

Compiled from "UserData.java"
public class lombok.UserData {
  public lombok.UserData();
}


After decompilation, you can see that it is the same as generating a parameterless constructor without annotation

Use @ ToString

public class lombok.UserData {
  public lombok.UserData();
  public java.lang.String toString();
}

After decompilation, you can see that the toString method is added, which is different from the native one

System.out.println(new UserData().toString());
// Native toString output
lombok.UserData@60e53b93 The reference address changes each time it is generated
// @ToString output
UserData(name=null, age=0, good=false)

Use @ EqualsAndHashCode

Compiled from "UserData.java"
public class lombok.UserData {
  public lombok.UserData();
  public boolean equals(java.lang.Object);
  protected boolean canEqual(java.lang.Object);
  public int hashCode();
}

After decompilation, you can see three methods of adding equals canEqual hashCode

Output compared with native

public static void main(String[] args) {
        UserData userData = new UserData();
        System.out.println(userData.equals(new UserData()));
        System.out.println(userData.canEqual(new UserData()));
        System.out.println(userData.hashCode());
    }
// Native output
false
// No canEqual method
1625635731
// @EqualsAndHashCode output
true
true
355159

Through the above output comparison, it is obvious that the annotated result is different from the original equals. It is recommended that_ Use with caution_

You can use Idea decompile to see the generated code logic, which is not shown here. If you are interested, you can try it yourself

Add @ Data annotation

Take a look at this lazy annotation, which is also the most widely used annotation @ Data

Compiled from "UserData.java"
public class lombok.UserData {
  public lombok.UserData();
  public java.lang.String getName();
  public int getAge();
  public boolean isGood();
  public void setName(java.lang.String);
  public void setAge(int);
  public void setGood(boolean);
  public boolean equals(java.lang.Object);
  protected boolean canEqual(java.lang.Object);
  public int hashCode();
  public java.lang.String toString();
}

After decompilation, it can be seen that it is an aggregate of @ Getter @Setter @EqualsAndHashCode @ToString

It is recommended to use it cautiously here, mainly because the code generated by @ EqualsAndHashCode annotation will affect the judgment of equal

Use @ NoArgsConstructor

Compiled from "UserData.java"
public class lombok.UserData {
  public lombok.UserData();
}


After decompilation, you can see the same as using @ RequiredArgsConstructor without annotation

Use @ AllArgsConstructor

Compiled from "UserData.java"
public class lombok.UserData {
  public lombok.UserData(java.lang.String, int, boolean);
}

After decompilation, it can be seen that there is no parameterless constructor, and a full parameter constructor is added

Using @ Builder

An internal class is added after compilation UserData$UserDataBuilder.class
Compiled from "UserData.java"
public class lombok.UserData$UserDataBuilder {
  lombok.UserData$UserDataBuilder();
  public lombok.UserData$UserDataBuilder name(java.lang.String);
  public lombok.UserData$UserDataBuilder age(int);
  public lombok.UserData$UserDataBuilder good(boolean);
  public lombok.UserData build();
  public java.lang.String toString();
}

Compiled from "UserData.java"
public class lombok.UserData {
  lombok.UserData(java.lang.String, int, boolean);
  public static lombok.UserData$UserDataBuilder builder();
}

A full parameter constructor and a builder method are generated

reference resources

https://projectlombok.org/

javap -verbose UserData

Classfile /***/classes/lombok/UserData.class
  Last modified 2021-4-13; size 1975 bytes
  MD5 checksum 3fe9c971d14ecbcecdc5be0c02e7907e
  Compiled from "UserData.java"
public class lombok.UserData
  minor version: 0
  major version: 52 // JDK version for plain clothes  
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool: // Constant pool
   #1 = Methodref          #22.#66        // java/lang/Object."<init>":()V
   #2 = Fieldref           #5.#67         // lombok/UserData.name:Ljava/lang/String;
   #3 = Fieldref           #5.#68         // lombok/UserData.age:I
   #4 = Fieldref           #5.#69         // lombok/UserData.good:Z
   #5 = Class              #70            // lombok/UserData
   #6 = Methodref          #5.#71         // lombok/UserData.canEqual:(Ljava/lang/Object;)Z
   #7 = Methodref          #5.#72         // lombok/UserData.getName:()Ljava/lang/String;
   #8 = Methodref          #22.#73        // java/lang/Object.equals:(Ljava/lang/Object;)Z
   #9 = Methodref          #5.#74         // lombok/UserData.getAge:()I
  #10 = Methodref          #5.#75         // lombok/UserData.isGood:()Z
  #11 = Methodref          #22.#76        // java/lang/Object.hashCode:()I
  #12 = Class              #77            // java/lang/StringBuilder
  #13 = Methodref          #12.#66        // java/lang/StringBuilder."<init>":()V
  #14 = String             #78            // UserData(name=
  #15 = Methodref          #12.#79        // java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
  #16 = String             #80            // , age=
  #17 = Methodref          #12.#81        // java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
  #18 = String             #82            // , good=
  #19 = Methodref          #12.#83        // java/lang/StringBuilder.append:(Z)Ljava/lang/StringBuilder;
  #20 = String             #84            // )
  #21 = Methodref          #12.#85        // java/lang/StringBuilder.toString:()Ljava/lang/String;
  #22 = Class              #86            // java/lang/Object
  #23 = Utf8               name
  #24 = Utf8               Ljava/lang/String;
  #25 = Utf8               age
  #26 = Utf8               I
  #27 = Utf8               good
  #28 = Utf8               Z
  #29 = Utf8               <init>
  #30 = Utf8               ()V
  #31 = Utf8               Code
  #32 = Utf8               LineNumberTable
  #33 = Utf8               LocalVariableTable
  #34 = Utf8               this
  #35 = Utf8               Llombok/UserData;
  #36 = Utf8               getName
  #37 = Utf8               ()Ljava/lang/String;
  #38 = Utf8               getAge
  #39 = Utf8               ()I
  #40 = Utf8               isGood
  #41 = Utf8               ()Z
  #42 = Utf8               setName
  #43 = Utf8               (Ljava/lang/String;)V
  #44 = Utf8               setAge
  #45 = Utf8               (I)V
  #46 = Utf8               setGood
  #47 = Utf8               (Z)V
  #48 = Utf8               equals
  #49 = Utf8               (Ljava/lang/Object;)Z
  #50 = Utf8               o
  #51 = Utf8               Ljava/lang/Object;
  #52 = Utf8               other
  #53 = Utf8               this$name
  #54 = Utf8               other$name
  #55 = Utf8               StackMapTable
  #56 = Class              #70            // lombok/UserData
  #57 = Class              #86            // java/lang/Object
  #58 = Utf8               canEqual
  #59 = Utf8               hashCode
  #60 = Utf8               PRIME
  #61 = Utf8               result
  #62 = Utf8               $name
  #63 = Utf8               toString
  #64 = Utf8               SourceFile
  #65 = Utf8               UserData.java
  #66 = NameAndType        #29:#30        // "<init>":()V
  #67 = NameAndType        #23:#24        // name:Ljava/lang/String;
  #68 = NameAndType        #25:#26        // age:I
  #69 = NameAndType        #27:#28        // good:Z
  #70 = Utf8               lombok/UserData
  #71 = NameAndType        #58:#49        // canEqual:(Ljava/lang/Object;)Z
  #72 = NameAndType        #36:#37        // getName:()Ljava/lang/String;
  #73 = NameAndType        #48:#49        // equals:(Ljava/lang/Object;)Z
  #74 = NameAndType        #38:#39        // getAge:()I
  #75 = NameAndType        #40:#41        // isGood:()Z
  #76 = NameAndType        #59:#39        // hashCode:()I
  #77 = Utf8               java/lang/StringBuilder
  #78 = Utf8               UserData(name=
  #79 = NameAndType        #87:#88        // append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
  #80 = Utf8               , age=
  #81 = NameAndType        #87:#89        // append:(I)Ljava/lang/StringBuilder;
  #82 = Utf8               , good=
  #83 = NameAndType        #87:#90        // append:(Z)Ljava/lang/StringBuilder;
  #84 = Utf8               )
  #85 = NameAndType        #63:#37        // toString:()Ljava/lang/String;
  #86 = Utf8               java/lang/Object
  #87 = Utf8               append
  #88 = Utf8               (Ljava/lang/String;)Ljava/lang/StringBuilder;
  #89 = Utf8               (I)Ljava/lang/StringBuilder;
  #90 = Utf8               (Z)Ljava/lang/StringBuilder;
{
  public lombok.UserData();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable: // Correspondence between source code line number and bytecode
        line 3: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Llombok/UserData;

  public java.lang.String getName();
    descriptor: ()Ljava/lang/String;
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: getfield      #2                  // Field name:Ljava/lang/String;
         4: areturn
      LineNumberTable:
        line 6: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Llombok/UserData;

  public int getAge();
    descriptor: ()I
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: getfield      #3                  // Field age:I
         4: ireturn
      LineNumberTable:
        line 8: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Llombok/UserData;

  public boolean isGood();
    descriptor: ()Z
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: getfield      #4                  // Field good:Z
         4: ireturn
      LineNumberTable:
        line 10: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Llombok/UserData;

  public void setName(java.lang.String);
    descriptor: (Ljava/lang/String;)V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=2, args_size=2
         0: aload_0
         1: aload_1
         2: putfield      #2                  // Field name:Ljava/lang/String;
         5: return
      LineNumberTable:
        line 3: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       6     0  this   Llombok/UserData;
            0       6     1  name   Ljava/lang/String;

  public void setAge(int);
    descriptor: (I)V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=2, args_size=2
         0: aload_0
         1: iload_1
         2: putfield      #3                  // Field age:I
         5: return
      LineNumberTable:
        line 3: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       6     0  this   Llombok/UserData;
            0       6     1   age   I

  public void setGood(boolean);
    descriptor: (Z)V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=2, args_size=2
         0: aload_0
         1: iload_1
         2: putfield      #4                  // Field good:Z
         5: return
      LineNumberTable:
        line 3: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       6     0  this   Llombok/UserData;
            0       6     1  good   Z

  public boolean equals(java.lang.Object);
    descriptor: (Ljava/lang/Object;)Z
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=5, args_size=2
         0: aload_1
         1: aload_0
         2: if_acmpne     7
         5: iconst_1
         6: ireturn
         7: aload_1
         8: instanceof    #5                  // class lombok/UserData
        11: ifne          16
        14: iconst_0
        15: ireturn
        16: aload_1
        17: checkcast     #5                  // class lombok/UserData
        20: astore_2
        21: aload_2
        22: aload_0
        23: invokevirtual #6                  // Method canEqual:(Ljava/lang/Object;)Z
        26: ifne          31
        29: iconst_0
        30: ireturn
        31: aload_0
        32: invokevirtual #7                  // Method getName:()Ljava/lang/String;
        35: astore_3
        36: aload_2
        37: invokevirtual #7                  // Method getName:()Ljava/lang/String;
        40: astore        4
        42: aload_3
        43: ifnonnull     54
        46: aload         4
        48: ifnull        65
        51: goto          63
        54: aload_3
        55: aload         4
        57: invokevirtual #8                  // Method java/lang/Object.equals:(Ljava/lang/Object;)Z
        60: ifne          65
        63: iconst_0
        64: ireturn
        65: aload_0
        66: invokevirtual #9                  // Method getAge:()I
        69: aload_2
        70: invokevirtual #9                  // Method getAge:()I
        73: if_icmpeq     78
        76: iconst_0
        77: ireturn
        78: aload_0
        79: invokevirtual #10                 // Method isGood:()Z
        82: aload_2
        83: invokevirtual #10                 // Method isGood:()Z
        86: if_icmpeq     91
        89: iconst_0
        90: ireturn
        91: iconst_1
        92: ireturn
      LineNumberTable:
        line 3: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      93     0  this   Llombok/UserData;
            0      93     1     o   Ljava/lang/Object;
           21      72     2 other   Llombok/UserData;
           36      57     3 this$name   Ljava/lang/Object;
           42      51     4 other$name   Ljava/lang/Object;
      StackMapTable: number_of_entries = 8
        frame_type = 7 /* same */
        frame_type = 8 /* same */
        frame_type = 252 /* append */
          offset_delta = 14
          locals = [ class lombok/UserData ]
        frame_type = 253 /* append */
          offset_delta = 22
          locals = [ class java/lang/Object, class java/lang/Object ]
        frame_type = 8 /* same */
        frame_type = 1 /* same */
        frame_type = 12 /* same */
        frame_type = 12 /* same */

  protected boolean canEqual(java.lang.Object);
    descriptor: (Ljava/lang/Object;)Z
    flags: ACC_PROTECTED
    Code:
      stack=1, locals=2, args_size=2
         0: aload_1
         1: instanceof    #5                  // class lombok/UserData
         4: ireturn
      LineNumberTable:
        line 3: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Llombok/UserData;
            0       5     1 other   Ljava/lang/Object;

  public int hashCode();
    descriptor: ()I
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=4, args_size=1
         0: bipush        59
         2: istore_1
         3: iconst_1
         4: istore_2
         5: aload_0
         6: invokevirtual #7                  // Method getName:()Ljava/lang/String;
         9: astore_3
        10: iload_2
        11: bipush        59
        13: imul
        14: aload_3
        15: ifnonnull     23
        18: bipush        43
        20: goto          27
        23: aload_3
        24: invokevirtual #11                 // Method java/lang/Object.hashCode:()I
        27: iadd
        28: istore_2
        29: iload_2
        30: bipush        59
        32: imul
        33: aload_0
        34: invokevirtual #9                  // Method getAge:()I
        37: iadd
        38: istore_2
        39: iload_2
        40: bipush        59
        42: imul
        43: aload_0
        44: invokevirtual #10                 // Method isGood:()Z
        47: ifeq          55
        50: bipush        79
        52: goto          57
        55: bipush        97
        57: iadd
        58: istore_2
        59: iload_2
        60: ireturn
      LineNumberTable:
        line 3: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      61     0  this   Llombok/UserData;
            3      58     1 PRIME   I
            5      56     2 result   I
           10      51     3 $name   Ljava/lang/Object;
      StackMapTable: number_of_entries = 4
        frame_type = 255 /* full_frame */
          offset_delta = 23
          locals = [ class lombok/UserData, int, int, class java/lang/Object ]
          stack = [ int ]
        frame_type = 255 /* full_frame */
          offset_delta = 3
          locals = [ class lombok/UserData, int, int, class java/lang/Object ]
          stack = [ int, int ]
        frame_type = 91 /* same_locals_1_stack_item */
          stack = [ int ]
        frame_type = 255 /* full_frame */
          offset_delta = 1
          locals = [ class lombok/UserData, int, int, class java/lang/Object ]
          stack = [ int, int ]

  public java.lang.String toString();
    descriptor: ()Ljava/lang/String;
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=1, args_size=1
         0: new           #12                 // class java/lang/StringBuilder
         3: dup
         4: invokespecial #13                 // Method java/lang/StringBuilder."<init>":()V
         7: ldc           #14                 // String UserData(name=
         9: invokevirtual #15                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        12: aload_0
        13: invokevirtual #7                  // Method getName:()Ljava/lang/String;
        16: invokevirtual #15                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        19: ldc           #16                 // String , age=
        21: invokevirtual #15                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        24: aload_0
        25: invokevirtual #9                  // Method getAge:()I
        28: invokevirtual #17                 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
        31: ldc           #18                 // String , good=
        33: invokevirtual #15                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        36: aload_0
        37: invokevirtual #10                 // Method isGood:()Z
        40: invokevirtual #19                 // Method java/lang/StringBuilder.append:(Z)Ljava/lang/StringBuilder;
        43: ldc           #20                 // String )
        45: invokevirtual #15                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        48: invokevirtual #21                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
        51: areturn
      LineNumberTable:
        line 3: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      52     0  this   Llombok/UserData;
}
SourceFile: "UserData.java"

Keywords: Java

Added by serg4444 on Tue, 08 Mar 2022 02:12:37 +0200