1. 为什么要有链式编程
当我们想方便的将其进行实例化和赋值,往往会调用其构造方法来创建对象。
但一个POJO有很多参数的时候,我们想灵活的为其赋值,往往需要调用其set方法,但在并发条件下,这种做法会将非完全初始化的对象暴漏给外界的其他线程,这样做会产生数据不全的风险。
所以我们采用更加安全的建造者模式,通过链式表达式创建新的对象。
2. 注意
1、@Builder不支持父类对象构建,建议使用@superBuilder进行代替。
2、@Accessors需要将属性chain = true,如此可将操作默认为get&set,令其可以支持链式表达。
3. @Builder
@SuperBuilder
public class Person1 {
private Long id;
private String username;
private String passwd;
}
编译后效果:
package com.testLombok.pojo;
public class Person1 {
private Long id;
private String username;
private String passwd;
protected Person1(Person1.Person1Builder<?, ?> b) {
this.id = b.id;
this.username = b.username;
this.passwd = b.passwd;
}
public static Person1.Person1Builder<?, ?> builder() {
return new Person1.Person1BuilderImpl();
}
private static final class Person1BuilderImpl extends Person1.Person1Builder<Person1, Person1.Person1BuilderImpl> {
private Person1BuilderImpl() {
}
protected Person1.Person1BuilderImpl self() {
return this;
}
public Person1 build() {
return new Person1(this);
}
}
public abstract static class Person1Builder<C extends Person1, B extends Person1.Person1Builder<C, B>> {
private Long id;
private String username;
private String passwd;
public Person1Builder() {
}
protected abstract B self();
public abstract C build();
public B id(Long id) {
this.id = id;
return this.self();
}
public B username(String username) {
this.username = username;
return this.self();
}
public B passwd(String passwd) {
this.passwd = passwd;
return this.self();
}
public String toString() {
return "Person1.Person1Builder(id=" + this.id + ", username=" + this.username + ", passwd=" + this.passwd + ")";
}
}
}
由此可以看出,在使用@Builder时,需要创建一个Build对象,再掉用其对应Build方法生成我们需要得到的对象,这样会占用更多的内存空间,代码也相对变得冗余。
具体使用代码:
EmsUser emsUser = EmsUser.builder().mobile("").email("").build();
4. @Accessors
@Accessors(chain = true)
@Data
public class Person2 {
private Long id;
private String username;
private String passwd;
}
编译后效果:
package com.testLombok.pojo;
public class Person2 {
private Long id;
private String username;
private String passwd;
public Person2() {
}
public Long getId() {
return this.id;
}
public String getUsername() {
return this.username;
}
public String getPasswd() {
return this.passwd;
}
public Person2 setId(Long id) {
this.id = id;
return this;
}
public Person2 setUsername(String username) {
this.username = username;
return this;
}
public Person2 setPasswd(String passwd) {
this.passwd = passwd;
return this;
}
public boolean equals(Object o) {
if (o == this) {
return true;
} else if (!(o instanceof Person2)) {
return false;
} else {
Person2 other = (Person2)o;
if (!other.canEqual(this)) {
return false;
} else {
label47: {
Object this$id = this.getId();
Object other$id = other.getId();
if (this$id == null) {
if (other$id == null) {
break label47;
}
} else if (this$id.equals(other$id)) {
break label47;
}
return false;
}
Object this$username = this.getUsername();
Object other$username = other.getUsername();
if (this$username == null) {
if (other$username != null) {
return false;
}
} else if (!this$username.equals(other$username)) {
return false;
}
Object this$passwd = this.getPasswd();
Object other$passwd = other.getPasswd();
if (this$passwd == null) {
if (other$passwd != null) {
return false;
}
} else if (!this$passwd.equals(other$passwd)) {
return false;
}
return true;
}
}
}
protected boolean canEqual(Object other) {
return other instanceof Person2;
}
public int hashCode() {
int PRIME = true;
int result = 1;
Object $id = this.getId();
int result = result * 59 + ($id == null ? 43 : $id.hashCode());
Object $username = this.getUsername();
result = result * 59 + ($username == null ? 43 : $username.hashCode());
Object $passwd = this.getPasswd();
result = result * 59 + ($passwd == null ? 43 : $passwd.hashCode());
return result;
}
public String toString() {
return "Person2(id=" + this.getId() + ", username=" + this.getUsername() + ", passwd=" + this.getPasswd() + ")";
}
}
借助简单的return this实现链式表达,代码实现简单规范,原理清晰透彻。
具体使用代码:
EmsUser emsUser = new EmsUser().setEmail("").setMobile("");
5. 如何选择
由于@Accessors仍为一个不稳定版本的注解,在长期迭代的项目中不推荐使用,建议使用@Builder
6. @Accessors使用中的空指针异常
java.lang.NullPointerException
at net.sf.cglib.core.ReflectUtils.getMethodInfo(ReflectUtils.java:424)
at net.sf.cglib.beans.BeanCopier$Generator.generateClass(BeanCopier.java:133)
at net.sf.cglib.core.DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:25)
at net.sf.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:216)
at net.sf.cglib.beans.BeanCopier$Generator.create(BeanCopier.java:90)
at net.sf.cglib.beans.BeanCopier.create(BeanCopier.java:50)
当借助工具对实体类进行反射浅拷贝时,会校验其set返回值是否为void,此时使用@Accessors便会出现异常
解决办法:
`BeanCopier.create` will throw exception when the `source` or `target` use `@Accessors(chain = true)` in lombok.
But `org.springframework.beans.BeanUtils.copyProperties(source, target);` has no problem.