Detailed use of Lombok and summary of its advantages and disadvantages

  • 2021-10-27 07:28:50
  • OfStack

What is Lombok

Lombok is an Java development plug-in, which can simplify tedious and tedious code through the annotations it defines, mainly for simple Java model objects (POJO).

The benefits are obvious, and you can save a lot of repetitive work, especially Getter/Setter, constructor methods, equals methods, and toString methods that need to be modified repeatedly when the attributes of the POJO class increase or decrease.

Moreover, Lombok deals with these contents at compile time, not through reflection mechanism, which has the advantage that it will not degrade the performance of the system.

Let's look at the specific use.

Installation of Lombok

The installation of Lombok is divided into two parts: the installation of Idea plug-in and the import of pom file in maven.

Step 1: Search for Lombok in the plug-in configuration of Idea or download the local installation in official website.

Step 2, introduce the dependency in pom, the current finest version 1.18. 10.


<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.10</version>
</dependency>

For some reason, I failed to install plug-in 1 with Idea, so I only introduced dependency in pom, which can also be used normally.

Use of Lombok

@Data

One of the most commonly used annotations of @ Data. Annotation on the class, provides getter/setter methods for all properties of the class, and also provides equals, canEqual, hashCode, toString methods.

What do you mean by offering here? That is, developers don't have to write the corresponding methods by hand, but Lombok will help you generate them.

The example of using @ Data is as follows. The most intuitive thing is that you don't have to write the getter/setter method.


package pojo;

public class User {
    private int id;
    private String name;
    private String pwd;

    public User(int id, String hello, String pwd) {
    }

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public String getPwd() {
        return pwd;
    }

    public void setId(int id) {
        this.id = id;
    }

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

    public void setPwd(String pwd) {
        this.pwd = pwd;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", pwd='" + pwd + '\'' +
                '}';
    }
}

@Data
public class User {
    private int id;
    private String name;
    private String pwd;

}

By contrast, the effect is obvious.

@Setter

Acts on an attribute and provides an setter method for the attribute; On the class, setter methods are provided for all properties of the class, and default constructors are provided.


public class Demo {
	private int id;
	@Setter
	private String remark;
}

@Setter
public class Demo {
	private int id;
	private String remark;
}

@Getter

Basically, the same @ Setter method is used, but the getter method is provided, so I won't repeat it here.

@Log4j

Acts on a class, providing the class with an log4j log object with the property name log.


@Log4j
public class Demo {
}

This attribute 1 is generally used on business processing classes such as Controller and Service. The same annotation is @ Log4j2, which, as its name implies, is for Log4j2.

@AllArgsConstructor

On a class, provide a constructor for the class that contains all of its parameters. Note that the default constructor will not be provided at this time.


@AllArgsConstructor
public class Demo {
	private int id;
	private String remark;
}

The effect is as follows:


public class Demo {
    private int id;
    private String remark;

    public Demo(final int id, final String remark) {
        this.id = id;
        this.remark = remark;
    }
}

@NoArgsConstructor

It acts on a class and provides a constructor without parameters. It can be used in conjunction with @ AllArgsConstructor, where two constructors are generated: the parameterless constructor and the fully parameterized constructor.

@EqualsAndHashCode

Acts on the class, generating equals, canEqual, hashCode methods. For specific effects, please refer to the initial @ Data effect.

@NonNull

Acts on a property, provides a non-null check for this parameter, and throws a null pointer exception if the parameter is null.


public class Demo {
	@NonNull
	private int id;
	private String remark;
}

@RequiredArgsConstructor

Acts on a class and generates constructors as parameters from all member variables in the class annotated with @ NonNull or decorated with final.

@Cleanup

Applies to a variable to ensure that the resource it represents is automatically closed, calling the resource's close () method by default, or using @ Cleanup ("methodName") if the resource has other closing methods.


public void jedisExample(String[] args) {
    try {
        @Cleanup Jedis jedis =   redisService.getJedis();
    } catch (Exception ex) {
        logger.error( " Jedis Anomaly : " ,ex)
    }
}

The effect is equivalent to:


package pojo;

public class User {
    private int id;
    private String name;
    private String pwd;

    public User(int id, String hello, String pwd) {
    }

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public String getPwd() {
        return pwd;
    }

    public void setId(int id) {
        this.id = id;
    }

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

    public void setPwd(String pwd) {
        this.pwd = pwd;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", pwd='" + pwd + '\'' +
                '}';
    }
}
0

@ToString

Acts on a class to generate an toString method with all parameters. See the toString method in @ Data.

@Value

Acts on a class, generates full-parameter constructors, getter methods, equals, hashCode, toString methods. Compared with @ Data, there are more full-parameter constructions and fewer default constructions, setter methods and canEqual methods.

What should be noted in this annotation is that the field will be decorated with final. Personally, I feel that it is out of control here, so it is not recommended to use it.

@SneakyThrows

It acts on the method, which is equivalent to adding an try-catch to the code in the method, and throwing an exception with Lombok. sneakyThrow (e) in catching exception catch. Use @ SneakyThrows (BizException. class) to specify that specific exceptions are thrown.


package pojo;

public class User {
    private int id;
    private String name;
    private String pwd;

    public User(int id, String hello, String pwd) {
    }

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public String getPwd() {
        return pwd;
    }

    public void setId(int id) {
        this.id = id;
    }

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

    public void setPwd(String pwd) {
        this.pwd = pwd;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", pwd='" + pwd + '\'' +
                '}';
    }
}
1

The effect is as follows:


package pojo;

public class User {
    private int id;
    private String name;
    private String pwd;

    public User(int id, String hello, String pwd) {
    }

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public String getPwd() {
        return pwd;
    }

    public void setId(int id) {
        this.id = id;
    }

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

    public void setPwd(String pwd) {
        this.pwd = pwd;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", pwd='" + pwd + '\'' +
                '}';
    }
}
2

@Synchronized

Acts on a class method or instance method with the same effect as synchronized. The difference is that the lock objects are different. For class methods and instance methods, the lock objects of synchronized keywords are class objects and this objects of classes respectively, while the lock objects of @ Synchronized are private static final objects lock and private final objects lock respectively. You can also specify a lock object.


public class FooExample { 

 private final Object readLock = new Object(); 

 @Synchronized 
 public static void hello() { 
     System.out.println("world");   
 } 

 @Synchronized("readLock") 
 public void foo() { 
   System.out.println("bar"); 
 } 

}

The effect is equivalent to:


package pojo;

public class User {
    private int id;
    private String name;
    private String pwd;

    public User(int id, String hello, String pwd) {
    }

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public String getPwd() {
        return pwd;
    }

    public void setId(int id) {
        this.id = id;
    }

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

    public void setPwd(String pwd) {
        this.pwd = pwd;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", pwd='" + pwd + '\'' +
                '}';
    }
}
4

val

Use val as the type declared by the local variable instead of the actual write type. When you do this, the type is inferred from the initialization expression.


package pojo;

public class User {
    private int id;
    private String name;
    private String pwd;

    public User(int id, String hello, String pwd) {
    }

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public String getPwd() {
        return pwd;
    }

    public void setId(int id) {
        this.id = id;
    }

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

    public void setPwd(String pwd) {
        this.pwd = pwd;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", pwd='" + pwd + '\'' +
                '}';
    }
}
5

The effect is as follows:


package pojo;

public class User {
    private int id;
    private String name;
    private String pwd;

    public User(int id, String hello, String pwd) {
    }

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public String getPwd() {
        return pwd;
    }

    public void setId(int id) {
        this.id = id;
    }

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

    public void setPwd(String pwd) {
        this.pwd = pwd;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", pwd='" + pwd + '\'' +
                '}';
    }
}
6

That is to say, in local variables, Lombok helps you infer the specific type, but it can only be used in local variables.

@Builder

For classes, @ Builder may be your favorite annotation if you prefer to use Builder for streaming operations.


package pojo;

public class User {
    private int id;
    private String name;
    private String pwd;

    public User(int id, String hello, String pwd) {
    }

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public String getPwd() {
        return pwd;
    }

    public void setId(int id) {
        this.id = id;
    }

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

    public void setPwd(String pwd) {
        this.pwd = pwd;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", pwd='" + pwd + '\'' +
                '}';
    }
}
7

The effect is as follows:


public class Demo {
    private int id;
    private String remark;

    Demo(final int id, final String remark) {
        this.id = id;
        this.remark = remark;
    }

    public static Demo.DemoBuilder builder() {
        return new Demo.DemoBuilder();
    }

    public static class DemoBuilder {
        private int id;
        private String remark;

        DemoBuilder() {
        }

        public Demo.DemoBuilder id(final int id) {
            this.id = id;
            return this;
        }

        public Demo.DemoBuilder remark(final String remark) {
            this.remark = remark;
            return this;
        }

        public Demo build() {
            return new Demo(this.id, this.remark);
        }

        public String toString() {
            return "Demo.DemoBuilder(id="   this.id   ", remark="   this.remark   ")";
        }
    }
}

Advantages and disadvantages of Lombok

Advantages:

1. It can automatically generate constructors in the form of annotations, such as getter/setter, equals, hashcode, toString and so on, which improves the development efficiency of the project
2. Make the code concise without paying too much attention to the corresponding methods
3. The maintenance of getter/setter methods generated for these attributes is also simplified when modifying the attributes

Disadvantages:

Strong X teammates
Because the use of Lombok requires developer 1 to install the corresponding plug-in in IDE. If no plug-in is installed, opening an Lombok-based project using IDE will prompt errors such as no method found. Causes the project to fail to compile. That is, if one person in the project team uses Lombok, the others must also install the IDE plug-in. Otherwise, there is no way to develop collaboratively. More importantly, if Lombok is used in one jar package we define, it is required that all applications that depend on this jar package must install plug-ins, which is very intrusive. Low readability and debugging of code
Using Lombok in the code really helps to reduce a lot of code, because Lombok helps to generate a lot of code automatically.
However, these codes will not be generated until the compilation stage, so in the development process, in fact, many codes are missing.
Extensive use of Lombok in code leads to much lower readability of code, and it also brings 1 definite problem to code debugging.
For example, if we want to know which classes refer to the getter method of a property in a class, it is not so simple. Have pits
Because Lombok makes code development very simple, it makes some developers over-rely on it. In the process of using Lombok, if you don't understand the underlying principles of various annotations, it is easy to produce unexpected results. As a simple example, we know that when we define a class using @ Data, it automatically generates the equals () method for us. However, if only @ Data is used instead of @ EqualsAndHashCode (callSuper=true), @ EqualsAndHashCode (callSuper=false) will be defaulted, and the generated equals () method will only compare the attributes of subclasses, and will not consider the attributes inherited from the parent class, regardless of whether the parent class attribute access is open or not. This may lead to unexpected results. Impact upgrade
Because Lombok is very intrusive to the code, it may bring a big problem, that is, it will affect our upgrade of JDK. According to the upgrade frequency of JDK, a new version will be released every six months, but Lombok is a third-party tool and maintained by the open source team, so its iteration speed cannot be guaranteed. Therefore, if we need to upgrade to a new version of JDK, if the features are not supported in Lombok, it will be affected. Another possible problem is that the upgrade of Lombok itself will be limited. Because an application may depend on multiple jar packages, and each jar package may depend on different versions of Lombok, it leads to the need for version arbitration in applications. As we know, version arbitration of jar packages is not so easy, and the probability of problems is also very high. Break the encapsulation
I think there are ways to avoid the above problems. However, there is another important reason why some people reject using Lombok, that is, it will break the encapsulation. As we all know, the three characteristics of Java include encapsulation, inheritance and polymorphism. If we use Lombok directly in the code, it will automatically help us generate getter, setter and other methods, which means that all parameters in a class automatically provide setting and reading methods.

Reference blog:
Detailed explanation of Java development artifact Lombok
Lombok Plug-in Installation and Simple Use Steps


Related articles: