Lombok最新最全解析

什么是Lombok


Project Lombok是一个java库,可以自动插入到编辑器和构建工具中,为java增添情趣。不要再编写另一个getter或equals方法,只需一个注释,您的类就有一个功能齐全的构建器、自动化您的日志记录变量等等。(避免重复造轮子)

运行原理

现有版本采用JSR 269规范(可插拔批注处里API)可以让我们修改编译过程,在编译期融入我们自己的东西,相比通过反射来获取注解,运行时代码效率降低等问题。所以在javac 解析成抽象语法树之后(AST),Lombok根据自己的注解处理器,动态修改AST,增加新的节点,最终通过生成字节码得以体现

优势与缺点

优点:通过注解的形式生成构造器,getter/setter, equals, hascode, toString等方法,提高开发效率让代码变得简洁。
缺点:

  • 不支持多种参数构造器的重载
  • 降低源码可读性和完整性
  • 需要在开发工具中安装对应的插件
  • 代码可调试性底
  • 影响对项目JDK的升级

注解示例

根据 官网分为稳定版和实验版进行说明
通过maven导入Lombok (截至2022/12/1 最新)

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

稳定版

val

// 使用 Lombok
val example = new ArrayList<String>();
val foo = example.get(0);
// 生成class文件
 final ArrayList<String> example = new ArrayList<String>();
 final String foo = example.get(0);

var

// 使用Lombok
var example = new ArrayList<String>();
var foo = example.get(0);
// 生成class文件
 ArrayList<String> example = new ArrayList<String>();
 String foo = example.get(0);

var 和 val 支持配置项
lombok.val.flagUsage = [warning | error] (默认: 未设置)
如果配置,Lombok会将val的任何使用标记为warning或error。
lombok.var.flagUsage = [warning | error] (默认: 未设置)
如果配置,Lombok会将var的任何使用标记为warning或error。
在不明确的情况下 初始化为null时会判断成java.lang.Object
对于复合类型,谨慎使用,避免与我们想象中的类型不一致 导致程序异常

@NonNull

// 使用Lombok
@NonNull Person person
// 生成class文件
   if (person == null) {
      throw new NullPointerException("person is marked non-null but is null");
    }

@Cleanup

// 使用Lombok
@Cleanup InputStream in = new FileInputStream(args[0]);
@Cleanup OutputStream out = new FileOutputStream(args[1]);
// 生成class文件
InputStream in = new FileInputStream(args[0]);
try {
  OutputStream out = new FileOutputStream(args[1]);
  try {
  }
 } finally {
   if (out != null) {
     out.close();
   }
 }
 } finally {
   if (in != null) {
     in.close();
   }
 }
}

@Getter/@Setter

// 使用Lombok
@Getter @Setter private int age;
@Setter(AccessLevel.PROTECTED) private String name;
// 生成class文件
  /**
   * Age of the person. Water is wet.
   *
   * @return The current value of this person's age. Circles are round.
   */
  public int getAge() {
    return age;
  }
  
  /**
   * Age of the person. Water is wet.
   *
   * @param age New value for this person's age. Sky is blue.
   */
  public void setAge(int age) {
    this.age = age;
  }
  /**
   * Changes the name of this person.
   *
   * @param name The new value.
   */
  protected void setName(String name) {
    this.name = name;
  }

@ToString

// 使用Lombok
import lombok.ToString;

@ToString( includeFieldNames=false) // 给ToStringExample 生成toString方法
public class ToStringExample {
  private static final int STATIC_VAR = 10;
  private String name;
  private Shape shape = new Square(5, 10);
  private String[] tags;
  @ToString.Exclude private int id; // 给ToStringExample 生成toString方法中去除id属性
  
  public String getName() {
    return this.name;
  }
  
  @ToString(callSuper=true, includeFieldNames=true) // 实现toString方法输出父类中继承的属性 和 形式为fieldName = fieldValue
  public static class Square extends Shape {
    private final int width, height;
    
    public Square(int width, int height) {
      this.width = width;
      this.height = height;
    }
  }
}

// 生成class文件

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.name;
  }
  
  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) + ")";
  }
}

支持的配置项
lombok.toString.includeFieldNames = [true | false] (default: true)
lombok为每个字段生成一个toString响应的片段,形式为fieldName = fieldValue。如果这个设置为false,lombok将省略字段的名称,并简单地部署所有字段值的逗号分隔的列表。
lombok.toString.doNotUseGetters = [true | false] (default: false)
如果设置为true,lombok在生成toString方法时将直接访问字段而不是使用getters(如果有的话)。
lombok.toString.callSuper = [call | skip | warn] (default: skip)
如果设置为call,则如果您的类扩展了某些内容,lombok将生成对toString的父类实现的调用。如果设置为skip,则不会生成此父类调用。如果设置为warn,则也不会生成此父类调用,但lombok会生成警告来告诉您。
lombok.toString.onlyExplicitlyIncluded = [true | false] (default: false)
如果设置为false(默认),那么所有字段(除非static、name以$开头,或者由于明显的原因被排除在外)都将作为toString中包含的默认内容集.。
@ToString.Exclude 将该属性排除在外
@ToString.Include 将该属性包含在内
lombok.toString.flagUsage = [warning | error] (default: not set)
Lombok将@ToString的任何使用标记为警告或错误(如果已配置)。

@EqualsAndHashCode

//使用Lombok

import lombok.EqualsAndHashCode;

@EqualsAndHashCode
public class EqualsAndHashCodeExample {
  private transient int transientVar = 10;
  private String name;
  private double score;
  @EqualsAndHashCode.Exclude private Shape shape = new Square(5, 10);
  private String[] tags;
  @EqualsAndHashCode.Exclude 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;
    }
  }
}
// 生成class文件
import java.util.Arrays;

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;
  }
  
  @Override public boolean equals(Object o) {
    if (o == this) return true;
    if (!(o instanceof EqualsAndHashCodeExample)) return false;
    EqualsAndHashCodeExample other = (EqualsAndHashCodeExample) o;
    if (!other.canEqual((Object)this)) return false;
    if (this.getName() == null ? other.getName() != null : !this.getName().equals(other.getName())) return false;
    if (Double.compare(this.score, other.score) != 0) return false;
    if (!Arrays.deepEquals(this.tags, other.tags)) return false;
    return true;
  }
  
  @Override public int hashCode() {
    final int PRIME = 59;
    int result = 1;
    final long temp1 = Double.doubleToLongBits(this.score);
    result = (result*PRIME) + (this.name == null ? 43 : this.name.hashCode());
    result = (result*PRIME) + (int)(temp1 ^ (temp1 >>> 32));
    result = (result*PRIME) + Arrays.deepHashCode(this.tags);
    return result;
  }
  
  protected boolean canEqual(Object other) {
    return other instanceof EqualsAndHashCodeExample;
  }
  
  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 boolean equals(Object o) {
      if (o == this) return true;
      if (!(o instanceof Square)) return false;
      Square other = (Square) o;
      if (!other.canEqual((Object)this)) return false;
      if (!super.equals(o)) return false;
      if (this.width != other.width) return false;
      if (this.height != other.height) return false;
      return true;
    }
    
    @Override public int hashCode() {
      final int PRIME = 59;
      int result = 1;
      result = (result*PRIME) + super.hashCode();
      result = (result*PRIME) + this.width;
      result = (result*PRIME) + this.height;
      return result;
    }
    
    protected boolean canEqual(Object other) {
      return other instanceof Square;
    }
  }
}

@NoArgsConstructor @RequiredArgsConstructor and @AllArgsConstructor

// 使用Lombok
import lombok.AccessLevel;
import lombok.RequiredArgsConstructor;
import lombok.AllArgsConstructor;
import lombok.NonNull;

@RequiredArgsConstructor(staticName = "of") // 生成该类下被final修饰或者non-null字段生成一个构造方法。
@AllArgsConstructor(access = AccessLevel.PROTECTED) // 构造方法的访问修饰符为PROTECTED 生成该类下全部属性的构造方法。
public class ConstructorExample<T> {
  private int x, y;
  @NonNull private T description;
  
  @NoArgsConstructor //生成无参的构造方法。
  public static class NoArgsExample {
    @NonNull private String field;
  }
}

// 生成class文件
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() {
    }
  }
}

重要场景:当一个bean类,注入其他bean的时候我们通常用@Autowired ,可以用@AllArgsConstructor或者@RequiredArgsConstructor来代替(实用)
当bean属性注入需要找类型为String名字是name的bean对象 需要使用@RequiredArgsConstructor 当使用@RequiredArgsConstructor 必须加上 final 或者 @NonNull修饰

特殊说明: 通常注解会有几个属性

staticName

生成的构造方法是私有的并且生成一个参数为final变量和@NonNull注解变量,返回类型为当前对象的静态方法 方法名为staticName 值

access

设置构造方法的访问修饰符,PUBLIC、MODULE、PROTECTED、PACKAGE、PRIVATE、NONE ,MODULE 是 Java 9 的新特性,NONE 表示不生成构造方法也不生成静态方法,即停用注解功能

onConstructor

列出的所有注解都放在生成的构造方法上
JDK 7 之前的写法是 onConstructor = @__({@Deprecated}),而 JDK 8 之后的写法是 onConstructor_ = {@Deprecated}

@Data

注在类上,提供类的get、set、equals、hashCode、canEqual、toString方法 合理使用,不要因为只用setter getter方法直接用 按需使用

// 使用 Lombok
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; // Set方法 访问修饰方法为 provided
  private double score;
  private String[] tags;
  
  @ToString(includeFieldNames=true) // toString方法 以FieldName=FieldValue对应
  @Data(staticConstructor="of") // 构造方法为私有 并生成静态方法返回当前对象 方法名为staticConstructor值
  public static class Exercise<T> {
    private final String name;
    private final T value;
  }
}
// 生成class文件

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;
    }
  }
}

@Value

作用于类 使所有的成员变量都是final 是 @ToString @EqualsAndHashCode @AllArgsConstructor @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) @Getter
在注解源码中只有一个属性

staticConstructor

使生成的构造方法私有化 并生成一个返回类型为当前对象的无参静态方法,方法名为staticConstructor值

// 使用Lombok

import lombok.AccessLevel;
import lombok.experimental.NonFinal;
import lombok.experimental.Value;
import lombok.experimental.With;
import lombok.ToString;

@Value public class ValueExample {
  String name;
  @With(AccessLevel.PACKAGE) @NonFinal int age; // With:生成方法名为with+属性名 返回全参构造方法的对象 修改当前属性的值  NonFinal:保持非final的字段
  double score;
  protected String[] tags;
  
  @ToString(includeFieldNames=true) // 生成ToString方法 以fieldname = fieldValue对应
  @Value(staticConstructor="of") // staticConstructor:构造方法为私有生成静态方法返回对象 方法名为staticConstructor值
  public static class Exercise<T> {
    String name;
    T value;
  }
}
// 生成class类
import java.util.Arrays;

public final class ValueExample {
  private final String name;
  private int age;
  private final double score;
  protected final String[] tags;
  
  @java.beans.ConstructorProperties({"name", "age", "score", "tags"})
  public ValueExample(String name, int age, double score, String[] tags) {
    this.name = name;
    this.age = age;
    this.score = score;
    this.tags = tags;
  }
  
  public String getName() {
    return this.name;
  }
  
  public int getAge() {
    return this.age;
  }
  
  public double getScore() {
    return this.score;
  }
  
  public String[] getTags() {
    return this.tags;
  }
  
  @java.lang.Override
  public boolean equals(Object o) {
    if (o == this) return true;
    if (!(o instanceof ValueExample)) return false;
    final ValueExample other = (ValueExample)o;
    final Object this$name = this.getName();
    final Object other$name = other.getName();
    if (this$name == null ? other$name != null : !this$name.equals(other$name)) 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;
  }
  
  @java.lang.Override
  public int hashCode() {
    final int PRIME = 59;
    int result = 1;
    final Object $name = this.getName();
    result = result * PRIME + ($name == null ? 43 : $name.hashCode());
    result = result * PRIME + this.getAge();
    final long $score = Double.doubleToLongBits(this.getScore());
    result = result * PRIME + (int)($score >>> 32 ^ $score);
    result = result * PRIME + Arrays.deepHashCode(this.getTags());
    return result;
  }
  
  @java.lang.Override
  public String toString() {
    return "ValueExample(name=" + getName() + ", age=" + getAge() + ", score=" + getScore() + ", tags=" + Arrays.deepToString(getTags()) + ")";
  }
  
  ValueExample withAge(int age) {
    return this.age == age ? this : new ValueExample(name, age, score, tags);
  }
  
  public static final 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;
    }
    
    @java.lang.Override
    public boolean equals(Object o) {
      if (o == this) return true;
      if (!(o instanceof ValueExample.Exercise)) return false;
      final Exercise<?> other = (Exercise<?>)o;
      final Object this$name = this.getName();
      final Object other$name = other.getName();
      if (this$name == null ? other$name != null : !this$name.equals(other$name)) return false;
      final Object this$value = this.getValue();
      final Object other$value = other.getValue();
      if (this$value == null ? other$value != null : !this$value.equals(other$value)) return false;
      return true;
    }
    
    @java.lang.Override
    public int hashCode() {
      final int PRIME = 59;
      int result = 1;
      final Object $name = this.getName();
      result = result * PRIME + ($name == null ? 43 : $name.hashCode());
      final Object $value = this.getValue();
      result = result * PRIME + ($value == null ? 43 : $value.hashCode());
      return result;
    }
    
    @java.lang.Override
    public String toString() {
      return "ValueExample.Exercise(name=" + getName() + ", value=" + getValue() + ")";
    }
  }
}

@Builder

对初学者有些难度 理解上费劲些 熟能生巧
使用建造者模式: 用来生成对象 通过对象链式赋值
内部生成步骤:

  1. 创建一个名为ThisClassBuilder的内部静态类 并具有和实体类相同的属性
  2. 目标类中的所有属性和未初始化的final字段 都会在构建其中创建对应属性
  3. 创建一个无参的default构造函数
  4. 对于实体类中的每个参数,都会对应创建类似于setter的方法 只不过方法名与该参数名像同。并且返回值是构建器本身(便于链式调用)
  5. 一个build() 方法 调用此方法 根据设置的值进行创建实体对象
  6. 生成一个toString()方法
  7. 创建一个builder() 方法 用来创建构建器
@Singular

作用于属性 想要这样来操作集合 需要使用
支持类型:java.util.Iterable,Collection, List
Set,SortedSet,NavigableSet
Map,SortedMap,NavigableMap
Guava’s com.google.common.collect:ImmutableCollection,ImmutableList,ImmutableSet,ImmutableSortedSet
ImmutableMap,ImmutableBiMap,ImmutableSortedMap,ImmutableTable

@Builder.Default

作用于属性,不需要初始化

// 使用Lombok
@Builder
public class User {
    private final Integer id;
    private final String zipCode = "123456";
    private String username;
    private String password;
    @Singular
    private List<String> hobbies;
}
// 生成class
public class User {
    private final Integer id;
    private final String zipCode = "123456";
    private String username;
    private String password;
    private List<String> hobbies;
    User(Integer id, String username, String password, List<String> hobbies) {
        this.id = id; this.username = username;
        this.password = password; this.hobbies = hobbies;
    }
 
    public static User.UserBuilder builder() {return new User.UserBuilder();}
 
    public static class UserBuilder {
        private Integer id;
        private String username;
        private String password;
        private ArrayList<String> hobbies;
        UserBuilder() {}
        public User.UserBuilder id(Integer id) { this.id = id; return this; }
        public User.UserBuilder username(String username) { this.username = username; return this; }
        public User.UserBuilder password(String password) { this.password = password; return this; }
 
        public User.UserBuilder hobby(String hobby) {
            if (this.hobbies == null) {
                this.hobbies = new ArrayList();
            }
            this.hobbies.add(hobby);
            return this;
        }
 
        public User.UserBuilder hobbies(Collection<? extends String> hobbies) {
            if (this.hobbies == null) {
                this.hobbies = new ArrayList();
            }
            this.hobbies.addAll(hobbies);
            return this;
        }
 
        public User.UserBuilder clearHobbies() {
            if (this.hobbies != null) {
                this.hobbies.clear();
            }
            return this;
        }
 
        public User build() {
            List hobbies;
            switch(this.hobbies == null ? 0 : this.hobbies.size()) {
            case 0:
                hobbies = Collections.emptyList();
                break;
            case 1:
                hobbies = Collections.singletonList(this.hobbies.get(0));
                break;
            default:
                hobbies = Collections.unmodifiableList(new ArrayList(this.hobbies));
            }
            return new User(this.id, this.username, this.password, hobbies);
        }
        public String toString() {
            return "User.UserBuilder(id=" + this.id + ", username=" + this.username + ", password=" + this.password + ", hobbies=" + this.hobbies + ")";
        }
    }
}

@SneakyThrows

作用于方法 将当前方法抛出的异常,包装成RuntimeException,骗过编译器 使得调用点可以不用显示处理异常信息

// 使用Lombok
import lombok.SneakyThrows;

public class SneakyThrowsExample implements Runnable {
  @SneakyThrows(UnsupportedEncodingException.class)
  public String utf8ToString(byte[] bytes) {
    return new String(bytes, "UTF-8");
  }
  
  @SneakyThrows
  public void run() {
    throw new Throwable();
  }
}
// 生成class

import lombok.Lombok;

public class SneakyThrowsExample implements Runnable {
  public String utf8ToString(byte[] bytes) {
    try {
      return new String(bytes, "UTF-8");
    } catch (UnsupportedEncodingException e) {
      throw Lombok.sneakyThrow(e);
    }
  }
  
  public void run() {
    try {
      throw new Throwable();
    } catch (Throwable t) {
      throw Lombok.sneakyThrow(t);
    }
  }
}

@Synchronized

作用于方法 锁住方法代码块 实现同步

// 使用Lombok
import lombok.Synchronized;

public class SynchronizedExample {
  private final Object readLock = new Object();
  
  @Synchronized
  public static void hello() {
    System.out.println("world");
  }
  
  @Synchronized
  public int answerToLife() {
    return 42;
  }
  
  @Synchronized("readLock")
  public void foo() {
    System.out.println("bar");
  }
}
// 生成class
public class SynchronizedExample {
  private static final Object $LOCK = new Object[0];
  private final Object $lock = new Object[0];
  private final Object readLock = new Object();
  
  public static void hello() {
    synchronized($LOCK) {
      System.out.println("world");
    }
  }
  
  public int answerToLife() {
    synchronized($lock) {
      return 42;
    }
  }
  
  public void foo() {
    synchronized(readLock) {
      System.out.println("bar");
    }
  }
}

@With

作用于类,生成多个with+变量名的方法(个数为所有成员变量 不包含@NonNull)
作用于变量 生成with+变量名的方法 返回当前对象 需要提供全参(不包含 静态变量)构造方法

// 使用Lombok
import lombok.AccessLevel;
import lombok.NonNull;
import lombok.With;

public class WithExample {
  @With(AccessLevel.PROTECTED) @NonNull private final String name;
  @With private final int age;
  
  public WithExample(@NonNull String name, int age) {
    this.name = name;
    this.age = age;
  }
}
// 生成class
import lombok.NonNull;

public class WithExample {
  private @NonNull final String name;
  private final int age;

  public WithExample(String name, int age) {
    if (name == null) throw new NullPointerException();
    this.name = name;
    this.age = age;
  }

  protected WithExample withName(@NonNull String name) {
    if (name == null) throw new java.lang.NullPointerException("name");
    return this.name == name ? this : new WithExample(name, age);
  }

  public WithExample withAge(int age) {
    return this.age == age ? this : new WithExample(name, age);
  }
}

@Getter(lazy=true)

Lombok 生成一个getter,第一次调用这个getter时计算一个值并从那时起缓存它。自动去管理线程安全的问题,不会存在重复赋值的问题,使用此功能,需要创建一个private final变量,并且使用运行成本高的表达式对其进行初始化

// 使用 Lombok
import lombok.Getter;

public class GetterLazyExample {
  @Getter(lazy=true) private final double[] cached = expensive();
  
  private double[] expensive() {
    double[] result = new double[1000000];
    for (int i = 0; i < result.length; i++) {
      result[i] = Math.asin(i);
    }
    return result;
  }
}
// 生成class
public class GetterLazyExample {
  private final java.util.concurrent.AtomicReference<java.lang.Object> cached = new java.util.concurrent.AtomicReference<java.lang.Object>();
  
  public double[] getCached() {
    java.lang.Object value = this.cached.get();
    if (value == null) {
      synchronized(this.cached) {
        value = this.cached.get();
        if (value == null) {
          final double[] actualValue = expensive();
          value = actualValue == null ? this.cached : actualValue;
          this.cached.set(value);
        }
      }
    }
    return (double[])(value == this.cached ? null : value);
  }
  
  private double[] expensive() {
    double[] result = new double[1000000];
    for (int i = 0; i < result.length; i++) {
      result[i] = Math.asin(i);
    }
    return result;
  }
}

@Log

生成一个logger字段

// 使用Lombok

import lombok.extern.java.Log;
import lombok.extern.slf4j.Slf4j;

@Log
public class LogExample {
  
  public static void main(String... args) {
    log.severe("Something's wrong here");
  }
}

@Slf4j
public class LogExampleOther {
  
  public static void main(String... args) {
    log.error("Something else is wrong here");
  }
}

@CommonsLog(topic="CounterLog")
public class LogExampleCategory {

  public static void main(String... args) {
    log.error("Calling the 'CounterLog' with a message");
  }
}
// 生成class

public class LogExample {
  private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(LogExample.class.getName());
  
  public static void main(String... args) {
    log.severe("Something's wrong here");
  }
}

public class LogExampleOther {
  private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LogExampleOther.class);
  
  public static void main(String... args) {
    log.error("Something else is wrong here");
  }
}

public class LogExampleCategory {
  private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog("CounterLog");

  public static void main(String... args) {
    log.error("Calling the 'CounterLog' with a message");
  }
}

实验版

@Accessors

可用于类及属性字段 用于生成getter和setter方法时的一些设置
属性

flent

为true: 生成的getter方法忽略get,并且setter方法返回对象本身,getter方法返回属性类型。
为false: @Data默认的属性.即(默认为false 生成的为getUserName(),为true时为userName() )

chain

为true: getter和setter方法和默认时一样,并且遵循驼峰命名,且setter方法返回的是对象本身,和Fient=true时返回类型一样
为false: @Data默认形式

prefix

属性值为String类型数组,意思就是比如prefix='user’且一个属性字段为String userName,则生成就为get方法:String getName();set方法:setName(String userName).

// 使用Lombok

import lombok.experimental.Accessors;
import lombok.Getter;
import lombok.Setter;

@Accessors(fluent = true)
public class AccessorsExample {
  @Getter @Setter
  private int age = 10;
}

class PrefixExample {
  @Accessors(prefix = "f") @Getter
  private String fName = "Hello, World!";
}
// 生成class

public class AccessorsExample {
  private int age = 10;
  
  public int age() {
    return this.age;
  }
  
  public AccessorsExample age(final int age) {
    this.age = age;
    return this;
  }
}

class PrefixExample {
  private String fName = "Hello, World!";
  
  public String getName() {
    return this.fName;
  }
}

@ExtensionMethod

作用于类 向类中添加方法 无需创建新的子类, 变量与方法参数,返回值类型必须一样
属性介绍

value

指定添加类

suppressBaseMethods

如果为 false,基础类型不能调用方法,默认为 true
如果 suppressBaseMethods = false
1、变量与方法参数、返回值的类型不能为基础类型
2、自定义方法不可与引用对象的方法重名(无法使用 变量.方法名)

 // 使用Lombok
 @ExtensionMethod(value = LongYiYi.class, suppressBaseMethods = true)
public class QiaoXin {
	public static void main(String[] args) {
		int num = 0;
		num = num.aaa();
		System.out.println(num);	// 输出结果为 1;
		"乔欣".print();
		List<String> list = new ArrayList<String>();
		list.add();
	}
}
class LongYiYi {
	public static int aaa(int num) {
		return ++num;
	}
	
	public static void print(String name) {
		System.out.println(name);
	}
	
	public static void add(List<String> list) {
		list.add("龙一一");
	}
}
 // 生成class文件
 public class QiaoXin {
  	public static void main(String[] args) {
    	int num = 0;
    	num = LongYiYi.aaa(num);
    	System.out.println(num);
    	LongYiYi.print("乔欣");
    	List list = new ArrayList();
    	LongYiYi.add(list);
  	}
}

@FieldDefaults

作用于类或枚举中的每个字段添加访问修饰符,为注释的类或枚举中的每个字段添加final
如果保持非final字段 可以用 @NonFinal
作用于实例字段中不添加final 需要使用@FieldDefaults(makeFinal=true)
@FieldDefaults(level=AccessLevel.PRIVATE)
任何还没有访问修饰符的字段(即任何看起来像包私有访问的字段)都被改变为具有适当的访问修饰符
任何必须保持包私有的字段都可以用@PackagePrivate

// 使用Lombok
import lombok.AccessLevel;
import lombok.experimental.FieldDefaults;
import lombok.experimental.NonFinal;
import lombok.experimental.PackagePrivate;

@FieldDefaults(makeFinal=true, level=AccessLevel.PRIVATE)
public class FieldDefaultsExample {
  public final int a;
  int b;
  @NonFinal int c;
  @PackagePrivate int d;
  
  FieldDefaultsExample() {
    a = 0;
    b = 0;
    d = 0;
  }
}
// 生成class
public class FieldDefaultsExample {
  public final int a;
  private final int b;
  private int c;
  final int d;
  
  FieldDefaultsExample() {
    a = 0;
    b = 0;
    d = 0;
  }
}

@Delegate

任何字段或无参数方法都可以用@Delegate来注解,让lombok生成转发对这个字段的调用(或调用这个方法的结果)的委托方法。

// 使用Lombok
import java.util.ArrayList;
import java.util.Collection;

import lombok.experimental.Delegate;

public class DelegationExample {
  private interface SimpleCollection {
    boolean add(String item);
    boolean remove(Object item);
  }
  
  @Delegate(types=SimpleCollection.class)
  private final Collection<String> collection = new ArrayList<String>();
}


class ExcludesDelegateExample {
  long counter = 0L;
  
  private interface Add {
    boolean add(String x);
    boolean addAll(Collection<? extends String> x);
  }
  
  @Delegate(excludes=Add.class)
  private final Collection<String> collection = new ArrayList<String>();
  
  public boolean add(String item) {
    counter++;
    return collection.add(item);
  }
  
  public boolean addAll(Collection<? extends String> col) {
    counter += col.size();
    return collection.addAll(col);
  }
}
// 生成class
import java.util.ArrayList;
import java.util.Collection;

public class DelegationExample {
  private interface SimpleCollection {
    boolean add(String item);
    boolean remove(Object item);
  }
  
  private final Collection<String> collection = new ArrayList<String>();
  
  @java.lang.SuppressWarnings("all")
  public boolean add(final java.lang.String item) {
    return this.collection.add(item);
  }
  
  @java.lang.SuppressWarnings("all")
  public boolean remove(final java.lang.Object item) {
    return this.collection.remove(item);
  }
}

class ExcludesDelegateExample {
  long counter = 0L;
  
  private interface Add {
    boolean add(String x);
    boolean addAll(Collection<? extends String> x);
  }
  
  private final Collection<String> collection = new ArrayList<String>();
  
  public boolean add(String item) {
    counter++;
    return collection.add(item);
  }
  
  public boolean addAll(Collection<? extends String> col) {
    counter += col.size();
    return collection.addAll(col);
  }
  
  @java.lang.SuppressWarnings("all")
  public int size() {
    return this.collection.size();
  }
  
  @java.lang.SuppressWarnings("all")
  public boolean isEmpty() {
    return this.collection.isEmpty();
  }
  
  @java.lang.SuppressWarnings("all")
  public boolean contains(final java.lang.Object arg0) {
    return this.collection.contains(arg0);
  }
  
  @java.lang.SuppressWarnings("all")
  public java.util.Iterator<java.lang.String> iterator() {
    return this.collection.iterator();
  }
  
  @java.lang.SuppressWarnings("all")
  public java.lang.Object[] toArray() {
    return this.collection.toArray();
  }
  
  @java.lang.SuppressWarnings("all")
  public <T extends .java.lang.Object>T[] toArray(final T[] arg0) {
    return this.collection.<T>toArray(arg0);
  }
  
  @java.lang.SuppressWarnings("all")
  public boolean remove(final java.lang.Object arg0) {
    return this.collection.remove(arg0);
  }
  
  @java.lang.SuppressWarnings("all")
  public boolean containsAll(final java.util.Collection<?> arg0) {
    return this.collection.containsAll(arg0);
  }
  
  @java.lang.SuppressWarnings("all")
  public boolean removeAll(final java.util.Collection<?> arg0) {
    return this.collection.removeAll(arg0);
  }
  
  @java.lang.SuppressWarnings("all")
  public boolean retainAll(final java.util.Collection<?> arg0) {
    return this.collection.retainAll(arg0);
  }
  
  @java.lang.SuppressWarnings("all")
  public void clear() {
    this.collection.clear();
  }
}

onMethod= / onConstructor= / onParam=

暂不介绍

@UtilityClass

作用于类 将类标记为final 并且类,内部类中的方法 字段 都标记为static

// 使用Lombok
import lombok.experimental.UtilityClass;

@UtilityClass
public class UtilityClassExample {
  private final int CONSTANT = 5;

  public int addSomething(int in) {
    return in + CONSTANT;
  }
}
// 生成class
public final class UtilityClassExample {
  private static final int CONSTANT = 5;

  private UtilityClassExample() {
    throw new java.lang.UnsupportedOperationException("This is a utility class and cannot be instantiated");
  }

  public static int addSomething(int in) {
    return in + CONSTANT;
  }
}

@Helper

作用于方法内部类,使内部类中的方法暴露在外面可以被直接调用

// 使用Lombok
import lombok.experimental.Helper;

public class HelperExample {
  int someMethod(int arg1) {
    int localVar = 5;

    @Helper class Helpers {
      int helperMethod(int arg) {
        return arg + localVar;
      }
    }

    return helperMethod(10);
  }
}
// 生成class
public class HelperExample {
  int someMethod(int arg1) {
    int localVar = 5;

    class Helpers {
      int helperMethod(int arg) {
        return arg + localVar;
      }
    }
    Helpers $Helpers = new Helpers();

    return $Helpers.helperMethod(10);
  }
}

@FieldNameConstants

生成了一个内部类 Fields

// 使用Lombok
import lombok.experimental.FieldNameConstants;
import lombok.AccessLevel;

@FieldNameConstants
public class FieldNameConstantsExample {
  private final String iAmAField;
  private final int andSoAmI;
  @FieldNameConstants.Exclude private final int asAmI;
}
// 生成class
public class FieldNameConstantsExample {
  private final String iAmAField;
  private final int andSoAmI;
  private final int asAmI;
  
  public static final class Fields {
    public static final String iAmAField = "iAmAField";
    public static final String andSoAmI = "andSoAmI";
  }
}

@SuperBuilder

(慎用)
@Builder 的升级版,不支持对基类成员属性的构造
属性
builderMethodName:创建内部静态类的方法名,默认值为 builder
buildMethodName:创建实体类的方法名,默认值为 build
toBuilder:设置为 true 可以对这个对象进行拷贝生成新的对象,可以再修改,默认为 false
setterPrefix:setter 方法的前缀
注意事项

  1. 基类和派生类不能同时存在 @Builder
  2. 如果基类使用了 @SuperBuilder,那么派生类必须存在 @SuperBuilder 或者写出参数为:基类Builder<?, ?> 的构造方法
  3. @SuperBuilder 并不像 @Builder 功能那么多,比如非 final 字段设置默认值,@SuperBuilder 并不支持
// 使用Lombok
@SuperBuilder
public class ParentClass {
    private final String a;
    private final String b;
}

@SuperBuilder
public class ChildClass extends ParentClass{
    private final String c;
}
// 生成class
ChildClass.builder().a("testA").b("testB").c("testC").build();

@Tolerate

任何方法或构造函数都可以用注释,@Tolerate并且lombok会像它不存在一样起作用。
缺点
难以支持递归委派

// 使用Lombok
import lombok.experimental.Tolerate;

public class TolerateExample {
    @Setter
    private Date date;

    @Tolerate
    public void setDate(String date) {
        this.date = Date.valueOf(date);
    }
}
// 生成class
public class TolerateExample {
    @Setter
    private Date date;

    public void setDateFromString(String date) {
        this.date = Date.valueOf(date);
    }
}

@Jacksonized

该@Jacksonized注释是一个附加注释的@Builder和@SuperBuilder。它会自动配置生成的生成器类,以供Jackson的反序列化使用。它只有在还存在a@Builder或a的上下文中出现时才起作用@SuperBuilder。否则会发出警告。

@StandardException

放置任何扩展了某些{@code java.lang.Throwable}类型的类,以添加4个常见异常构造函数

// 使用Lombok
import lombok.experimental.StandardException;

@StandardException
public class ExampleException extends Exception {
}
// 生成class

public class ExampleException extends Exception {
    public ExampleException() {
        this(null, null);
    }

    public ExampleException(String message) {
        this(message, null);
    }

    public ExampleException(Throwable cause) {
        this(cause != null ? cause.getMessage() : null, cause);
    }

    public ExampleException(String message, Throwable cause) {
        super(message);
        if (cause != null) super.initCause(cause);
    }
}

实验版 (删除或增强注解) 慎用 暂不介绍

@Value: promoted

@Builder: promoted

@Wither: renamed to @With, and promoted

var

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

听不见你的名字

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值