lombok introduction, use, summary

1 Lombok Background

The official described as follows:

Project Lombok makes java a spicier language by adding 'handlers' that know how to build and compile simple, boilerplate-free, not-quite-java code.

Roughly meaning Lombok by adding some "process" that allows java become simple and fast.

2 Lombok Use

Lombok can be a simple form of annotations to simplify the java code , increase development efficiency of the developer. Such as development often need to write a javabean, need to take the time to add the corresponding getter / setter , and perhaps to write a constructor, equals and other methods, and the need to maintain, for a long time when a large number of property getter / setter methods occur, these seemed very long without much technical content, once modify the properties, it is prone to forget to change the mistakes of the corresponding method.

Annotations can Lombok manner, at compile time automatically generated constructor property, getter / setter, equals, hashcode , toString method . It appears that there is no magic getter and setter methods in the source code, but there are getter and setter methods in the compiled byte code file. This eliminates the need to manually rebuild the trouble code, making the code look more succinctly.

Lombok is used with reference to jar packages, you can at the official website ( https://projectlombok.org/download ) download jar package can also be used to add a dependency maven:

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.16.20</version>
    <scope>provided</scope>
</dependency>

Next, we analyze the specific use of Lombok in annotations.

2.1 @Data

@Data annotation on the class, setter / getter, equals, canEqual, hashCode, toString method automatically generates classes for all properties, such as the final attribute, no attribute setter method for the generation.

Official examples are as follows:

import lombok.AccessLevel;
import lombok.Setter;
import lombok.Data;
import lombok.ToString;

@Data public class DataExample {
  private final String name;
  @Setter(AccessLevel.PACKAGE) private int age;
  private double score;
  private String[] tags;
  
  @ToString(includeFieldNames=true)
  @Data(staticConstructor="of")
  public static class Exercise<T> {
    private final String name;
    private final T value;
  }
}

Without the use of Lombok, is achieved as follows:

 import java.util.Arrays;

public class DataExample {
  private final String name;
  private int age;
  private double score;
  private String[] tags;
  
  public DataExample(String name) {
    this.name = name;
  }
  
  public String getName() {
    return this.name;
  }
  
  void setAge(int age) {
    this.age = age;
  }
  
  public int getAge() {
    return this.age;
  }
  
  public void setScore(double score) {
    this.score = score;
  }
  
  public double getScore() {
    return this.score;
  }
  
  public String[] getTags() {
    return this.tags;
  }
  
  public void setTags(String[] tags) {
    this.tags = tags;
  }
  
  @Override public String toString() {
    return "DataExample(" + this.getName() + ", " + this.getAge() + ", " + this.getScore() + ", " + Arrays.deepToString(this.getTags()) + ")";
  }
  
  protected boolean canEqual(Object other) {
    return other instanceof DataExample;
  }
  
  @Override public boolean equals(Object o) {
    if (o == this) return true;
    if (!(o instanceof DataExample)) return false;
    DataExample other = (DataExample) o;
    if (!other.canEqual((Object)this)) return false;
    if (this.getName() == null ? other.getName() != null : !this.getName().equals(other.getName())) return false;
    if (this.getAge() != other.getAge()) return false;
    if (Double.compare(this.getScore(), other.getScore()) != 0) return false;
    if (!Arrays.deepEquals(this.getTags(), other.getTags())) return false;
    return true;
  }
  
  @Override public int hashCode() {
    final int PRIME = 59;
    int result = 1;
    final long temp1 = Double.doubleToLongBits(this.getScore());
    result = (result*PRIME) + (this.getName() == null ? 43 : this.getName().hashCode());
    result = (result*PRIME) + this.getAge();
    result = (result*PRIME) + (int)(temp1 ^ (temp1 >>> 32));
    result = (result*PRIME) + Arrays.deepHashCode(this.getTags());
    return result;
  }
  
  public static class Exercise<T> {
    private final String name;
    private final T value;
    
    private Exercise(String name, T value) {
      this.name = name;
      this.value = value;
    }
    
    public static <T> Exercise<T> of(String name, T value) {
      return new Exercise<T>(name, value);
    }
    
    public String getName() {
      return this.name;
    }
    
    public T getValue() {
      return this.value;
    }
    
    @Override public String toString() {
      return "Exercise(name=" + this.getName() + ", value=" + this.getValue() + ")";
    }
    
    protected boolean canEqual(Object other) {
      return other instanceof Exercise;
    }
    
    @Override public boolean equals(Object o) {
      if (o == this) return true;
      if (!(o instanceof Exercise)) return false;
      Exercise<?> other = (Exercise<?>) o;
      if (!other.canEqual((Object)this)) return false;
      if (this.getName() == null ? other.getValue() != null : !this.getName().equals(other.getName())) return false;
      if (this.getValue() == null ? other.getValue() != null : !this.getValue().equals(other.getValue())) return false;
      return true;
    }
    
    @Override public int hashCode() {
      final int PRIME = 59;
      int result = 1;
      result = (result*PRIME) + (this.getName() == null ? 43 : this.getName().hashCode());
      result = (result*PRIME) + (this.getValue() == null ? 43 : this.getValue().hashCode());
      return result;
    }
  }
}

2.2 @Getter/@Setter

If you think @Data too cruel (because @Data collection @ ToString, @ EqualsAndHashCode, @ Getter / @ Setter, all the features @ RequiredArgsConstructor of) the fine is not enough, you can use @ Getter / @ Setter annotation, this annotation on the property, you can automatically generate Getter / Setter method corresponding attributes, for example:

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

public class GetterSetterExample {

  @Getter @Setter private int age = 10;
  
  @Setter(AccessLevel.PROTECTED) private String name;
  
  @Override public String toString() {
    return String.format("%s (age: %d)", name, age);
  }
}

If you do not use Lombok:

 public class GetterSetterExample {

  private int age = 10;

  private String name;
  
  @Override public String toString() {
    return String.format("%s (age: %d)", name, age);
  }
  
  public int getAge() {
    return age;
  }
  
  public void setAge(int age) {
    this.age = age;
  }
  
  protected void setName(String name) {
    this.name = name;
  }
}

2.3 @NonNull

The annotation used on a property or constructor, Lombok is non-empty generates a statement can be used to verify the parameters, can help prevent a null pointer.

Examples are as follows:

import lombok.NonNull;

public class NonNullExample extends Something {
  private String name;
  
  public NonNullExample(@NonNull Person person) {
    super("Hello");
    this.name = person.getName();
  }
}

Do not use Lombok:

import lombok.NonNull;

public class NonNullExample extends Something {
  private String name;
  
  public NonNullExample(@NonNull Person person) {
    super("Hello");
    if (person == null) {
      throw new NullPointerException("person");
    }
    this.name = person.getName();
  }
}

2.4 @Cleanup

The notes can help us to automatically call close () method, greatly simplifies the code.

Examples are as follows:

import lombok.Cleanup;
import java.io.*;

public class CleanupExample {
  public static void main(String[] args) throws IOException {
    @Cleanup InputStream in = new FileInputStream(args[0]);
    @Cleanup OutputStream out = new FileOutputStream(args[1]);
    byte[] b = new byte[10000];
    while (true) {
      int r = in.read(b);
      if (r == -1) break;
      out.write(b, 0, r);
    }
  }
}

Without the use of Lombok, the following is required:

import java.io.*;

public class CleanupExample {
  public static void main(String[] args) throws IOException {
    InputStream in = new FileInputStream(args[0]);
    try {
      OutputStream out = new FileOutputStream(args[1]);
      try {
        byte[] b = new byte[10000];
        while (true) {
          int r = in.read(b);
          if (r == -1) break;
          out.write(b, 0, r);
        }
      } finally {
        if (out != null) {
          out.close();
        }
      }
    } finally {
      if (in != null) {
        in.close();
      }
    }
  }
}

2.5 @EqualsAndHashCode

By default, it will use all non-static (non-static) and non-transient (non-transient) attribute is generated and equals hasCode, can also exclude annotation to exclude some properties.

Examples are as follows:

import lombok.EqualsAndHashCode;

@EqualsAndHashCode(exclude={"id", "shape"})
public class EqualsAndHashCodeExample {
  private transient int transientVar = 10;
  private String name;
  private double score;
  private Shape shape = new Square(5, 10);
  private String[] tags;
  private int id;
  
  public String getName() {
    return this.name;
  }
  
  @EqualsAndHashCode(callSuper=true)
  public static class Square extends Shape {
    private final int width, height;
    
    public Square(int width, int height) {
      this.width = width;
      this.height = height;
    }
  }
}

2.6 @ToString

Use @ToString annotation class, generates a Lombok is toString () method, by default, will output class names, all attributes (attribute defines the order will follow), divided by a comma.

By includeFieldNamesparameter set to true, you can clear the output of toString () property. This is a bit convoluted, look through the code will be more clearly some.

Example of use in Lombok:

import lombok.ToString;

@ToString(exclude="id")
public class ToStringExample {
  private static final int STATIC_VAR = 10;
  private String name;
  private Shape shape = new Square(5, 10);
  private String[] tags;
  private int id;
  
  public String getName() {
    return this.getName();
  }
  
  @ToString(callSuper=true, includeFieldNames=true)
  public static class Square extends Shape {
    private final int width, height;
    
    public Square(int width, int height) {
      this.width = width;
      this.height = height;
    }
  }
}

Lombok sample does not use the following:

import java.util.Arrays;

public class ToStringExample {
  private static final int STATIC_VAR = 10;
  private String name;
  private Shape shape = new Square(5, 10);
  private String[] tags;
  private int id;
  
  public String getName() {
    return this.getName();
  }
  
  public static class Square extends Shape {
    private final int width, height;
    
    public Square(int width, int height) {
      this.width = width;
      this.height = height;
    }
    
    @Override public String toString() {
      return "Square(super=" + super.toString() + ", width=" + this.width + ", height=" + this.height + ")";
    }
  }
  
  @Override public String toString() {
    return "ToStringExample(" + this.getName() + ", " + this.shape + ", " + Arrays.deepToString(this.tags) + ")";
  }
}

2.7 @NoArgsConstructor, @RequiredArgsConstructor and @AllArgsConstructor

No argument constructor, some parameters configured, full-argument constructor. Lombok not achieve more argument constructor overload .

Lombok sample code is as follows:

import lombok.AccessLevel;
import lombok.RequiredArgsConstructor;
import lombok.AllArgsConstructor;
import lombok.NonNull;

@RequiredArgsConstructor(staticName = "of")
@AllArgsConstructor(access = AccessLevel.PROTECTED)
public class ConstructorExample<T> {
  private int x, y;
  @NonNull private T description;
  
  @NoArgsConstructor
  public static class NoArgsExample {
    @NonNull private String field;
  }
}

Lombok sample does not use the following:

 public class ConstructorExample<T> {
  private int x, y;
  @NonNull private T description;
  
  private ConstructorExample(T description) {
    if (description == null) throw new NullPointerException("description");
    this.description = description;
  }
  
  public static <T> ConstructorExample<T> of(T description) {
    return new ConstructorExample<T>(description);
  }
  
  @java.beans.ConstructorProperties({"x", "y", "description"})
  protected ConstructorExample(int x, int y, T description) {
    if (description == null) throw new NullPointerException("description");
    this.x = x;
    this.y = y;
    this.description = description;
  }
  
  public static class NoArgsExample {
    @NonNull private String field;
    
    public NoArgsExample() {
    }
  }
}

3 Lombok analysis works

Will find use in the process of Lombok, just add the appropriate annotation, no longer need to write any code for this purpose. Auto-generated code in the end is how to generate it?

The core is the place to comment on the resolution. JDK5 the introduction of notes, but also provides two analytical methods.

  • Parsing runtime

You can parse the annotations must be set @Retention runtime RUNTIME, so that you can get the annotation by reflection. java.lang, reflect reflection package provides an interface AnnotatedElement, the interface defines several methods to obtain information notes, Class, Constructor, Field, Method, Package and so implements the interface, the reflection will be very familiar friend should familiar with this analytical method.

  • Compile-time parsing

There are two mechanisms to resolve compile-time, respectively, under the simple description:

1)Annotation Processing Tool

Since JDK5 apt to produce, JDK7 been marked as expired, is not recommended for use in JDK8 has been completely removed from JDK6 start, you can replace it with Pluggable Annotation Processing API, apt to be replaced are mainly two reasons:

  • api in com.sun.mirror under non-standard package
  • Not integrated into javac, the need for additional run

2)Pluggable Annotation Processing API

JSR 269 from JDK6 added, as an alternative apt, and it solves two problems are apt, javac in the implementation of the program will call implementation of the API, so that we can make some enhancements to the compiler, then execute javac the process is as follows: 
Write pictures described here

On Lombok is essentially a realization of " JSR 269 API " program. In the process of using javac, which have an effect process is as follows:

  1. javac source code analysis, generates an abstract syntax tree (AST)
  2. During operation calls to achieve a "JSR 269 API" program of Lombok
  3. At this time, the respective tree node for AST Lombok on a first processing step is obtained, where to find the class @Data annotation corresponding syntax tree (AST), and then modify the syntax tree (AST), increased defines getter and setter methods
  4. javac using the modified abstract syntax tree (AST) generated bytecode file, that is, to add new class node (block)

Lombok have read the source code to achieve the corresponding annotations are HandleXXX, such as realized when HandleGetter.handle () @Getter annotations. There are other ways to achieve this using libraries, such as Google Auto , Dagger and so on.

4. Lombok advantages and disadvantages

advantage:

  1. Annotations can form automatically generated constructor, getter / setter, equals, hashcode, toString other methods to improve the efficiency of development of certain
  2. Let code becomes simple, not too much to pay attention to the appropriate method
  3. When making changes properties, but also simplifies maintenance of these properties generated getter / setter methods

Disadvantages:

  1. It does not support multiple overloaded constructor parameters
  2. While eliminating the need to manually create trouble getter / setter methods, but greatly reduces the readability and integrity of the source code, reducing the comfort of reading the source code
  3. IDE plug-in installation is required to use

5. Summary

Although Lombok has many advantages, but more similar to one kind Lombok IDE plug, projects need to rely on a corresponding jar package. Lombok dependent jar package because to use it in the comments compiled, why it is similar to plug-in? Because during use, eclipse or IntelliJ IDEA will need to install the plug-in, change the byte code generation, that is, it is changed to the java grammatical variations by operating the AST (Abstract Syntax Tree) when the compiler. Unlike spring dependency injection, or as is characteristic of an ORM mybatis runtime, but the characteristics of compile time. I personally feel most uncomfortable place to be is dependent on plug-ins! Because Lombok just eliminating some trouble artificially generated code, but there are shortcuts to assist the IDE generates getter / setter methods, it is also very convenient.

God know there was a large number of published views of Lombok on peace:

这是一种低级趣味的插件,不建议使用。JAVA发展到今天,各种插件层出不穷,如何甄别各种插件的优劣?能从架构上优化你的设计的,能提高应用程序性能的 ,
实现高度封装可扩展的..., 像lombok这种,像这种插件,已经不仅仅是插件了,改变了你如何编写源码,事实上,少去了代码你写上去又如何? 
如果JAVA家族到处充斥这样的东西,那只不过是一坨披着金属颜色的屎,迟早会被其它的语言取代。

Although the word processor but do not rough rough, imagine a project like this is very much similar to the plug Lombok, personally I feel really greatly reduces the comfort of reading the source code.

Although not very recommended to write in property getter / setter some business code, but in actual combat in multi-year projects, sometimes by giving getter / setter plus a little bit of business code, the code can greatly simplify certain business scenarios. The so-called trade-offs, perhaps this time to give up certain norms, get great convenience.

I am very convinced that a philosophy, any programming language or plug-ins are only just a tool, even if another powerful tool also lies with the person, like millet plus rifles still win the same reason aircraft artillery. Combined with specific business scenarios and the actual situation of the project without the blind pursuit of technology on the tall, fit is crucial.

Lombok has its unique advantages and disadvantages it shunned, familiar with its advantages and disadvantages, flexible use in actual combat is king.

Reprinted from: https://www.cnblogs.com/heyonggang/p/8638374.html

Guess you like

Origin blog.csdn.net/qq_34569497/article/details/93978217