lombok Tutorial

 


Lombok introduction, usage and summary
https://www.cnblogs.com/heyonggang/p/8638374.html

Lombok introduction, use, working principle, advantages and disadvantages
https://www.jianshu.com/p/453c379c94bd

Notes @ Slf4j use
https://www.jianshu.com/p/6e137ee836a1

Use the correct method @ Slf4j of
https://blog.csdn.net/cslucifer/article/details/80953400

 _________________________________________________________

 

Starting simultaneously: http://www.yuanrengu.com/index.php/20180324.html

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 in a simple form to simplify the comment java code to improve 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 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:

Copy the code
 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;
  }
}
Copy the code

Without the use of Lombok, is achieved as follows:

Copy the code
 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;
    }
  }
}
Copy the code

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:

Copy the code
 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);
  }
}
Copy the code

If you do not use Lombok:

Copy the code
 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;
  }
}
Copy the code

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:

Copy the code
import lombok.NonNull;

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

Do not use Lombok:

Copy the code
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();
  }
}
Copy the code

2.4 @Cleanup

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

Examples are as follows:

Copy the code
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);
    }
  }
}
Copy the code

Without the use of Lombok, the following is required:

Copy the code
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();
      }
    }
  }
}
Copy the code

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:

Copy the code
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;
    }
  }
}
Copy the code

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:

Copy the code
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;
    }
  }
}
Copy the code

Lombok sample does not use the following:

Copy the code
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) + ")";
  }
}
Copy the code

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:

Copy the code
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;
  }
}
Copy the code

Lombok sample does not use the following:

Copy the code
 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() {
    }
  }
}
Copy the code

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

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:

This is a vulgar plug, not recommended. JAVA development today, the endless variety of plug-ins, how to identify the pros and cons of various plug-ins? From the architecture to optimize your design, can improve the performance of the application program, 
to achieve highly scalable package ..., lombok like this, like this plug-in, the plug has not only changed how you write source code In fact, less to the code you write up how?
If JAVA family full of such things everywhere, it was just a lump of feces dressed in metallic colors, sooner or later it will be replaced by other languages.

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.

reference:

https://projectlombok.org/features/

https://github.com/rzwitserloot/lombok?spm=a2c4e.11153940.blogcont59972.5.2aeb6d32hayLHv

https://www.zhihu.com/question/42348457

https://blog.csdn.net/ghsau/article/details/52334762

 

 

Starting simultaneously: http://www.yuanrengu.com/index.php/20180324.html

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 in a simple form to simplify the comment java code to improve 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 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:

Copy the code
 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;
  }
}
Copy the code

Without the use of Lombok, is achieved as follows:

Copy the code
 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;
    }
  }
}
Copy the code

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:

Copy the code
 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);
  }
}
Copy the code

If you do not use Lombok:

Copy the code
 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;
  }
}
Copy the code

2.3 @NonNull

该注解用在属性或构造器上,Lombok会生成一个非空的声明,可用于校验参数,能帮助避免空指针。

示例如下:

Copy the code
import lombok.NonNull;

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

不使用Lombok:

Copy the code
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();
  }
}
Copy the code

2.4 @Cleanup

该注解能帮助我们自动调用close()方法,很大的简化了代码。

示例如下:

Copy the code
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);
    }
  }
}
Copy the code

如不使用Lombok,则需如下:

Copy the code
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();
      }
    }
  }
}
Copy the code

2.5 @EqualsAndHashCode

默认情况下,会使用所有非静态(non-static)和非瞬态(non-transient)属性来生成equals和hasCode,也能通过exclude注解来排除一些属性。

示例如下:

Copy the code
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;
    }
  }
}
Copy the code

2.6 @ToString

类使用@ToString注解,Lombok会生成一个toString()方法,默认情况下,会输出类名、所有属性(会按照属性定义顺序),用逗号来分割。

通过将includeFieldNames参数设为true,就能明确的输出toString()属性。这一点是不是有点绕口,通过代码来看会更清晰些。

使用Lombok的示例:

Copy the code
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;
    }
  }
}
Copy the code

不使用Lombok的示例如下:

Copy the code
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) + ")";
  }
}
Copy the code

2.7 @NoArgsConstructor, @RequiredArgsConstructor and @AllArgsConstructor

无参构造器、部分参数构造器、全参构造器。Lombok没法实现多种参数构造器的重载。

Lombok示例代码如下:

Copy the code
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;
  }
}
Copy the code

不使用Lombok的示例如下:

Copy the code
 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() {
    }
  }
}
Copy the code

3 Lombok工作原理分析

会发现在Lombok使用的过程中,只需要添加相应的注解,无需再为此写任何代码。自动生成的代码到底是如何产生的呢?

核心之处就是对于注解的解析上。JDK5引入了注解的同时,也提供了两种解析方式。

  • 运行时解析

运行时能够解析的注解,必须将@Retention设置为RUNTIME,这样就可以通过反射拿到该注解。java.lang,reflect反射包中提供了一个接口AnnotatedElement,该接口定义了获取注解信息的几个方法,Class、Constructor、Field、Method、Package等都实现了该接口,对反射熟悉的朋友应该都会很熟悉这种解析方式。

  • 编译时解析

编译时解析有两种机制,分别简单描述下:

1)Annotation Processing Tool

apt自JDK5产生,JDK7已标记为过期,不推荐使用,JDK8中已彻底删除,自JDK6开始,可以使用Pluggable Annotation Processing API来替换它,apt被替换主要有2点原因:

  • api都在com.sun.mirror非标准包下
  • 没有集成到javac中,需要额外运行

2)Pluggable Annotation Processing API

JSR 269自JDK6加入,作为apt的替代方案,它解决了apt的两个问题,javac在执行的时候会调用实现了该API的程序,这样我们就可以对编译器做一些增强,这时javac执行的过程如下: 
Write pictures described here

Lombok本质上就是一个实现了“JSR 269 API”的程序。在使用javac的过程中,它产生作用的具体流程如下:

  1. javac对源代码进行分析,生成了一棵抽象语法树(AST)
  2. 运行过程中调用实现了“JSR 269 API”的Lombok程序
  3. 此时Lombok就对第一步骤得到的AST进行处理,找到@Data注解所在类对应的语法树(AST),然后修改该语法树(AST),增加getter和setter方法定义的相应树节点
  4. javac使用修改后的抽象语法树(AST)生成字节码文件,即给class增加新的节点(代码块)

拜读了Lombok源码,对应注解的实现都在HandleXXX中,比如@Getter注解的实现时HandleGetter.handle()。还有一些其它类库使用这种方式实现,比如Google AutoDagger等等。

4. Lombok的优缺点

优点:

  1. 能通过注解的形式自动生成构造器、getter/setter、equals、hashcode、toString等方法,提高了一定的开发效率
  2. 让代码变得简洁,不用过多的去关注相应的方法
  3. 属性做修改时,也简化了维护为这些属性所生成的getter/setter方法等

缺点:

  1. 不支持多种参数构造器的重载
  2. 虽然省去了手动创建getter/setter方法的麻烦,但大大降低了源代码的可读性和完整性,降低了阅读源代码的舒适度

5. 总结

Lombok虽然有很多优点,但Lombok更类似于一种IDE插件,项目也需要依赖相应的jar包。Lombok依赖jar包是因为编译时要用它的注解,为什么说它又类似插件?因为在使用时,eclipse或IntelliJ IDEA都需要安装相应的插件,在编译器编译时通过操作AST(抽象语法树)改变字节码生成,变向的就是说它在改变java语法。它不像spring的依赖注入或者mybatis的ORM一样是运行时的特性,而是编译时的特性。这里我个人最感觉不爽的地方就是对插件的依赖!因为Lombok只是省去了一些人工生成代码的麻烦,但IDE都有快捷键来协助生成getter/setter等方法,也非常方便。

知乎上有位大神发表过对Lombok的一些看法:

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

虽然话糙但理确实不糙,试想一个项目有非常多类似Lombok这样的插件,个人觉得真的会极大的降低阅读源代码的舒适度。

虽然非常不建议在属性的getter/setter写一些业务代码,但在多年项目的实战中,有时通过给getter/setter加一点点业务代码,能极大的简化某些业务场景的代码。所谓取舍,也许就是这时的舍弃一定的规范,取得极大的方便。

我现在非常坚信一条理念,任何编程语言或插件,都仅仅只是工具而已,即使工具再强大也在于用的人,就如同小米加步枪照样能赢飞机大炮的道理一样。结合具体业务场景和项目实际情况,无需一味追求高大上的技术,适合的才是王道。

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

reference:

https://projectlombok.org/features/

https://github.com/rzwitserloot/lombok?spm=a2c4e.11153940.blogcont59972.5.2aeb6d32hayLHv

https://www.zhihu.com/question/42348457

https://blog.csdn.net/ghsau/article/details/52334762

Guess you like

Origin www.cnblogs.com/kelelipeng/p/11326621.html