使用 Lombok 消除冗余 getter 和 setter 代码

3,099 阅读3分钟
原文链接: sawyersun.github.io

问题描述

我们平时在写代码(POJO)的时候,经常需要生成getter和setter方法,以及hascode、tostring和equals等代码。虽然有IDE帮助我们一键生成,但仍然有些麻烦,并且会显得代码十分臃肿。 偶然的机会,我发现了Lombok Project。该项目通过使用注解,消除冗余的java代码。

如何使用

添加依赖

针对Maven工程,添加如下依赖:


    org.projectlombok
    lombok
    1.16.10

针对Gradle工程,添加如下依赖:

compile group: 'org.projectlombok', name: 'lombok', version: '1.16.10'

如果不使用构建工具,可以从官网下载页面下载jar包,并加载到classpath中。

开启annotation processing

Lombok是在编译时期,自动生成所需方法的,所以需要开启annotation processing。本人常用IDE是IntelliJ IDEA,在settings中找到如下设置,勾选Enable annotation processing。

另外,为了使IntelliJ IDEA支持Lombok,还需要安装其插件。

实例

@Getter和@Setter

public class Person {
    @Getter
    @Setter
    private boolean employed;
    @Getter
    @Setter(AccessLevel.PROTECTED)
    private String name;
    public String say(){
        return getName();
    }
    }

上述代码等价于如下Java源码

public class Person {
    private boolean employed;
    private String name;
	public boolean isEmployed() {
	    return employed;
	}
	public void setEmployed(final boolean employed) {
	    this.employed = employed;
	}
	public String getName(){
		return name;
	}
	protected void setName(final String name) {
	    this.name = name;
	}
    public String say(){
        return getName();
    }
    }

可以看到@Getter@Setter帮助我们少写了很多代码。其中,这一对属性都是可以设置AccessLevel,表明该方法的访问范围,可选值有PUBLICMODULEPROTECTEDPACKAGEPRIVATENONE。另外,在say()中调用getName()不会引起IDE报错,但是没有输入提示。

@ToString

@ToString(callSuper=true,exclude="someExcludedField")
public class Foo extends Bar {
    private boolean someBoolean = true;
    private String someStringField;
    private float someExcludedField;
    }

等价于如下Java源码:

public class Foo extends Bar {
    private boolean someBoolean = true;
    private String someStringField;
    private float someExcludedField;

    @java.lang.Override
    public java.lang.String toString() {
        return "Foo(super=" + super.toString() +
            ", someBoolean=" + someBoolean +
            ", someStringField=" + someStringField + ")";
    }
    }

显然,@Tostring用于生成tostring()方法。默认情况下,所有非静态的字段都会以name-value对的格式输出。但是可以使用exclude则用于排除掉某个字段。另外一个属性callSuper表明包括父类的字段

@EqualsAndHashCode

@EqualsAndHashCode(callSuper=true,exclude={"address","city","state","zip"})
public class Person extends SentientBeing {
    enum Gender { Male, Female }
    @NonNull private String name;
    @NonNull private Gender gender;

    private String ssn;
    private String address;
    private String city;
    private String state;
    private String zip;
    }

等价于如下Java源码:

public class Person extends SentientBeing {

    enum Gender {
    }
    @NonNull
    private String name;
    @NonNull
    private Gender gender;
    private String ssn;
    private String address;
    private String city;
    private String state;
    private String zip;

    @java.lang.Override    public boolean equals(final java.lang.Object o) {
        if (o == this) return true;
        if (o == null) return false;
        if (o.getClass() != this.getClass()) return false;
        if (!super.equals(o)) return false;
        final Person other = (Person)o;
        if (this.name == null ? other.name != null : !this.name.equals(other.name)) return false;
        if (this.gender == null ? other.gender != null : !this.gender.equals(other.gender)) return false;
        if (this.ssn == null ? other.ssn != null : !this.ssn.equals(other.ssn)) return false;
        return true;
    }

    @java.lang.Override    public int hashCode() {
        final int PRIME = 31;
        int result = 1;
        result = result * PRIME + super.hashCode();
        result = result * PRIME + (this.name == null ? 0 : this.name.hashCode());
        result = result * PRIME + (this.gender == null ? 0 : this.gender.hashCode());
        result = result * PRIME + (this.ssn == null ? 0 : this.ssn.hashCode());
        return result;
    }
    }

@EqualsAndHashCode帮我们实现了强大的equals()hashCode()方法。其中callSuperexclude用法和@ToString一样。

@Data

@Data是一个包含@ToString, @EqualsAndHashCode, @Getter@Setter功能的注解,就不贴代码了。其中,@Data有一个staticConstructor属性,接受一个字符串为参数。它的作用是使构造函数为private,并暴露一个静态工厂方法产生对象。

更多实例和用法,可以参考官方文档

缺点

虽然,使用Lombok可以省去生成setter和getter等方法的麻烦,但也会大大降低源文件的可读性和完整性,对不使用Lombok的人造成不必要的麻烦。所以使用与否,还是见仁见智。