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
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"