Lombok最新最全解析

news2024/9/23 15:33:22

Lombok目录

  • 什么是Lombok
  • 运行原理
  • 优势与缺点
  • 注解示例
    • 稳定版
      • val
      • var
      • @NonNull
      • @Cleanup
      • @Getter/@Setter
      • @ToString
      • @EqualsAndHashCode
      • @NoArgsConstructor @RequiredArgsConstructor and @AllArgsConstructor
        • staticName
        • access
        • onConstructor
      • @Data
      • @Value
        • staticConstructor
      • @Builder
        • @Singular
        • @Builder.Default
      • @SneakyThrows
      • @Synchronized
      • @With
      • @Getter(lazy=true)
      • @Log
    • 实验版
      • @Accessors
        • flent
        • chain
        • prefix
      • @ExtensionMethod
        • value
        • suppressBaseMethods
      • @FieldDefaults
      • @Delegate
      • onMethod= / onConstructor= / onParam=
      • @UtilityClass
      • @Helper
      • @FieldNameConstants
      • @SuperBuilder
      • @Tolerate
      • @Jacksonized
      • @StandardException
    • 实验版 (删除或增强注解) 慎用 暂不介绍
      • @Value: promoted
      • @Builder: promoted
      • @Wither: renamed to @With, and promoted
      • var

什么是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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/57317.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MySQL Linux服务器快照克隆引起的binlog日志无法正常删除导致文件系统满

最近&#xff0c;一个mysql数据库Linux服务器文件系统空间满&#xff0c;查看是binlog消耗绝大部分空间&#xff1b;经了解mysql数据库每天进行全备并删除1天前binlog日志&#xff1b;然而&#xff0c;2022.11.15日开始的binlog均没删除&#xff0c;后续了解到linux服务器被快照…

全都会!预测蛋白质标注!创建讲义!解释数学公式!最懂科学的智能NLP模型Galactica尝鲜 ⛵

&#x1f4a1; 作者&#xff1a;韩信子ShowMeAI &#x1f4d8; 机器学习实战系列&#xff1a;https://www.showmeai.tech/tutorials/41 &#x1f4d8; 深度学习实战系列&#xff1a;https://www.showmeai.tech/tutorials/42 &#x1f4d8; 自然语言处理实战系列&#xff1a;htt…

图片里的文字如何提取?试试这几种提取方法

最近收到了一些小伙伴的私信&#xff0c;他们收到了对方发送过来的图片&#xff0c;觉得图片上的文字信息比较重要&#xff0c;但是又不知道有什么快速的方法能提取到图片中的文字。平时你们遇到这种情况会怎么做呢&#xff1f;今天我给大家分享几个可以将图片转为文字的方法&a…

JVM调优之StringTable调优

jdk1.8之后&#xff0c;JVM内存结构如下 所谓的StringTable&#xff0c;即字符串常量池&#xff08;以下简称串池&#xff09;&#xff0c;存放在堆内存中。 我们先介绍一下intern方法 String s "ab"; //将这个字符串对象尝试放入串池&#xff0c;如果有则并不会放…

VMware下载与安装教程(详细)

虚拟机VMware下载与安装教程1. VMware下载2. VMware的安装1. VMware下载 Vmware官网 官网节目如下 直接点击 DOWNLOAD FOR FREE 之后会跳转到如下界面&#xff0c;可以选择版本&#xff08;目前最新版是17.x)&#xff0c;然后点击转至下载就会转到详细下载界面 根据自己的…

TortoiseGit安装和配置详细说明

一、TortoiseGit 简介 TortoiseGit 是免费开源的。 TortoiseGit 支持你执行常规任务&#xff0c;例如 commit、显示日志、区分两个版本、创建分支和标签、创建补丁等。 网站&#xff1a;tortoisegit.org下载&#xff1a;tortoisegit.org/Download文件&#xff1a;tortoisegi…

vue3移动端适配的解决方案

文章目录前言一、使用插件① 纯wap项目效果&#xff1a;Demo&#xff1a;② pc&wap混合项目&#xff08;我放弃了&#xff09;二、老方案效果&#xff1a;Demo&#xff1a;前言 最近在给公司内部做一个BBS论坛&#xff0c;需要在电脑和手机上都可以操作&#xff0c;所以需…

Kotlin高仿微信-第57篇-VIP管理列表

Kotlin高仿微信-项目实践58篇详细讲解了各个功能点&#xff0c;包括&#xff1a;注册、登录、主页、单聊(文本、表情、语音、图片、小视频、视频通话、语音通话、红包、转账)、群聊、个人信息、朋友圈、支付服务、扫一扫、搜索好友、添加好友、开通VIP等众多功能。 Kotlin高仿…

[附源码]Python计算机毕业设计Django家庭整理服务管理系统

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

微服务绕不过的坎-服务雪崩

引言 书接上篇 微服务外交官-Feign &#xff0c;讲完了SpringCloud Alibaba 远程调用组件Feign之后&#xff0c;接下来讲微服务项目绕不开的问题&#xff1a;服务雪崩。 概念 微服务架构应用设计其目的之一是为了应对高并发环境&#xff0c;那问题来&#xff0c;高并发环境会…

[附源码]计算机毕业设计医院挂号住院管理系统Springboot程序

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

BBR 数学模型直观展示

看 BBR 的理想图示&#xff1a; 但现实中数据包到达并非绝对均匀&#xff0c;考虑统计突发&#xff0c;实际情况如下&#xff1a; ​后文将 Delivery Rate 设为 B(Bandwidth)&#xff0c;将 RTT 设为 D(Delay)。 B/inflt 曲线一定上凸&#xff0c;可想象 1 个 inflt 只有一种…

HTML+CSS+JS网页设计期末课程大作业 DW个人博客网站制作 web前端开发技术 web课程设计 网页规划与设计

&#x1f389;精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业…

并发编程知识总结

并发编程知识总结 最近学习了&#xff1a;冰河《深入理解高并发编程》&#xff1b;《并发编程的艺术》&#xff1b; 特此简要对学习做了部分总结&#xff0c;方便后续对并发编程知识的完善和巩固&#xff1b; 若想深入了解学习&#xff0c;可阅读上述参考原著&#xff1b; 线…

基于蝙蝠优化算法的电力系统经济调度研究(Matlab代码实现)

&#x1f352;&#x1f352;&#x1f352;欢迎关注&#x1f308;&#x1f308;&#x1f308; &#x1f4dd;个人主页&#xff1a;我爱Matlab &#x1f44d;点赞➕评论➕收藏 养成习惯&#xff08;一键三连&#xff09;&#x1f33b;&#x1f33b;&#x1f33b; &#x1f34c;希…

刷题5-合并两个有序数组

刷题5-合并两个有序数组 解题思路&#xff1a; 把数组nums2的元素复制到数组nums1中&#xff0c;然后利用Java的Arrays.sort()数组排序&#xff0c;默认从小到大 核心代码&#xff1a; class Solution {public void merge(int[] nums1,int m,int[] nums2,int n){for(int i0…

Learning From Documents in the Wild to Improve Document Unwarping论文学习笔记

1 广告 论文2022年发表在SIGGRAPH顶会上。 预训练出来的模型有139M。 对文档的去扭曲变形效果在我们调研的深度学习模型里面算是最好的。 2 摘要 文档图像去扭曲是文档数字化和分析的重要内容。最先进的方法依靠纯合成数据来训练深度网络进行去扭曲。因此&#xff0c;经过训…

为 Go 开发配置Visual Studio Code

在本快速入门中&#xff0c;你将安装和配置 Go for Visual Studio Code 扩展。 在 2020 年 Go 开发人员调查结果中&#xff0c;41% 的受访者选择Visual Studio Code作为他们最喜欢的 Go 编辑器。 这使得Visual Studio Code成为 Go 开发人员最常用的编辑器。 Visual Studio Co…

中间代码生成(Intermediate Code Generation)

中间代码生成&#xff08;Intermediate Code Generation&#xff09;申明语句的翻译类型表达式申明式语句翻译简单赋值语句的翻译数组引用的翻译控制流语句的翻译控制流语句及其SDT布尔表达式及其SDT控制流语句翻译的例子布尔表达式和控制流表达式的回填switch语句的翻译过程调…

游戏开发32课 typescript super

super 在类的方法中super就表示当前类的父类。 如果在子类中写了构造函数&#xff0c;在子类构造函数中必须对父类的构造函数进行调用。 例子 (function() { // 父类 class Animal { name: string; constructor(name: string) { this.na…