05. 《Lombok 实战 —— @Data & @Value》

x33g5p2x  于2021-12-25 转载在 其他  
字(3.8k)|赞(0)|评价(0)|浏览(547)

1. @Data

1.1 @Data 实战使用

@Data是一个方便的快捷方式注释,它将@ToString@EqualsAndHashCode@Getter/@Setter@RequiredArgsConstructor的特性捆绑在一起。换句话说,@Data生成通常与简单POJOsbeans配合使用,它会进行以下操作:

  • 生成所有字段的getter,所有非final字段的setter
  • 实现相应类字段的toStringequals和hashCode
  • 构造方法将初始化所有没有初始化值的final字段,和所有使用@NonNull标记却没有初始化值的非final字段,从而确保字段永远不为空。
    估计你听着会有点绕,先来一个小菜常常鲜!
@Data
public class User {
    private final Integer id;
    private final String zipCode = "215500";
    @NonNull
    private String username;
    private String password;
}

// 编译后:
public class User {
    private final Integer id;
    private final String zipCode = "215500";
    @NonNull
    private String username;
    private String password;

    // 生成带有未初始化的 final 字段,以及标有 @NonNull 的字段
    public User(Integer id, @NonNull String username) {
        if (username == null) {
            throw new NullPointerException("username is marked @NonNull but is null");
        } else {
            this.id = id;
            this.username = username;
        }
    }

    public Integer getId() { return this.id; }
    public String getZipCode() {
        this.getClass();
        return "215500";
    }
    @NonNull
    public String getUsername() { return this.username; }
    public String getPassword() { return this.password; }

    // 只生成非 final 的字段的 setter 方法
    public void setUsername(@NonNull String username) {
        if (username == null) {
            throw new NullPointerException("username is marked @NonNull but is null");
        } else {
            this.username = username;
        }
    }
    public void setPassword(String password) { this.password = password; }
	// 省略 toString,canEquals,equals,hashCode 相关代码
}

看到编译后地代码,可以明确地看到为我们生成了所有参数的getter&setterconstructortoStringhashCode。你可能会说@Data一个注解就能满足实际工作需求,莫急,听我慢慢道来……

现在我们再来解释一下上面说的几条生成规则:

  • 可以看到所有的字段的getter都被生成,非finalsetter方法被生成。(这主要是因为,在构造方法中对final字段进行了初始化,要知道final字段一旦被初始化后,将不能再被修改)

  • 实现相应类字段的toStringequals,和hashCode,这没得说。

  • 再看最后一个,再生成构造器时,会生成带有这样两种参数的构造器:

  • 实体类有未被初始化的 final字段

  • 实体类中标有@NonNull注解的字段

1.2 @Data 注解配置详解

当我看到@Data的注解源码时,心里是抵触的,不愿接受的,这么好用的功能,为啥就不能丰富一下呢?

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface Data {
	// 使用静态构造方法,私有实体构造器,通过 staticConstructor 配置静态构造方法的名称
	String staticConstructor() default "";
}
1.3 @Data 使用注意事项
  • gettersetter默认是public的,如果需要改变修饰符请使用@Setter@Getter
  • transient类型的变量不会被hashcodeequals使用,静态变量也会被跳过;
  • 虽然@Data注解非常有用,但是它没有与其他注解相同的控制粒度。@Data提供了一个可以生成静态工厂的单一参数,将staticConstructor参数设置为所需要的名称,Lombok自动生成的构造函数设置为私有,并提供公开的给定名称的静态工厂方法@Data(staticConstructor=”of”)
  • 同时使用@Data@AllArgsConstructor后 ,默认的无参构造函数失效,如果需要它,要重新设置 @NoArgsConstructor
1.4 @Data 全局配置

也是抵触的,啥配置也没提供!

lombok.data.flagUsage = [warning | error] (default: not set)

2. @Value

Immutable classes made very easy.

@Value promoted to the main lombok package since lombok v0.12.0.

2.1 @Value 实战使用

@Value注解用于修饰类,相当于是@Data的不可变形式,因为字段都被修饰为privatefinal,默认的情况下不会生成settter。还有一点更狠的,默认类本身也是final的,不能被继承。
官方给出:实际上@Value相当于:final @ToString @EqualsAndHashCode @AllArgsConstructor @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) @Getter

先不说那么多,小试牛刀一下:

@Value
public class User {
    private final Integer id;
    private final String zipCode = "215500";
    @NonNull
    private String username;
    private String password;
}
// 编译后:
public final class User {
    private final Integer id;
    private final String zipCode = "215500";
    @NonNull
    private final String username;
    private final String password;

    public User(Integer id, @NonNull String username, String password) {
        if (username == null) {
            throw new NullPointerException("username is marked @NonNull but is null");
        } else {
            this.id = id;
            this.username = username;
            this.password = password;
        }
    }

    public Integer getId() { return this.id; }
    public String getZipCode() {
        this.getClass();
        return "215500";
    }
    @NonNull
    public String getUsername() { return this.username; }
    public String getPassword() { return this.password; }

	// 省略 toString,canEquals,equals,hashCode 相关代码
}

在编译后地代码中,没有发现setter方法,会生成一个带有所有的非final字段和未初始化的final字段的构造器。

生成相应的toString,canEquals,equals,hashCode方法

2.2 @Value 注解详解

多么痛的领悟!感觉@Data和@Value都是潜力股

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface Value {
	// 使用静态构造方法,私有实体构造器,通过 staticConstructor 配置静态构造方法的名称
	String staticConstructor() default "";
}
2.3 @Value 全局配置

这个全局配置没啥好说的……

lombok.value.flagUsage = [warning | error] (default: not set)

参考文档

相关文章