赞
踩
lombok是一个编译级别的插件,它可以在项目编译的时候生成一些代码。在很多工具类的项目中都有这个功能。比如dagger。
通俗的说,lombok可以通过注解来标示生成getter settter等代码。我们自然可以通过编译器比如IDEA的Generate生成,为啥要用这个?
在项目开发阶段,一个class的属性是一直变化的,今天可能增加一个字段,明天可能删除一个字段。每次变化都需要修改对应的模板代码。另外,有的class的字段超级多,多到一眼看不完。如果加上模板代码,更难一眼看出来。更有甚者,由于字段太多,想要使用builder来创建。手动创建builder和字段和原来的类夹杂在一起,看起来真的难受。lombok的@Builder即可解决这个问题。
引入就是加入lombok的jar包。
直接加入依赖
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.20</version>
</dependency>
下载lombok
下载地址:https://projectlombok.org/downloads/lombok.jar
或者访问官网下载 https://projectlombok.org/
在IDEA里使用需要添加一个插件。在插件里搜索lombok,安装,重启。
IDEA里需要在设置中启用annotation processors。
最简单的,最常用的,最直观的使用就是getter setter方法。
import java.util.Date; import lombok.AccessLevel; import lombok.Getter; import lombok.Setter; public class GetterSetterExample { @Getter @Setter private int age = 10; @Getter @Setter private boolean active; @Getter @Setter private Boolean none; @Getter @Setter private Date date; @Setter(AccessLevel.PROTECTED) private String name; @Override public String toString() { return String.format("%s (age: %d)", name, age); } @SuppressWarnings("unused") public static void main(String[] args) { GetterSetterExample example = new GetterSetterExample(); example.setActive(true); example.setAge(123); example.setDate(new Date()); example.setName("abc"); example.setNone(false); System.out.println(example); Date date = example.getDate(); Boolean none = example.getNone(); boolean active = example.isActive(); } }
简单使用没有问题,深入一点可以看到有些特殊设定。比如javadoc.
编译后的结果如下:
import java.io.PrintStream; import java.util.Date; public class GetterSetterExample { public int getAge() { return this.age; } public void setAge(int age) { this.age = age; } private int age = 10; private boolean active; private Boolean none; private Date date; private String name; public boolean isActive() { return this.active; } public void setActive(boolean active) { this.active = active; } public Boolean getNone() { return this.none; } public void setNone(Boolean none) { this.none = none; } public Date getDate() { return this.date; } public void setDate(Date date) { this.date = date; } protected void setName(String name) { this.name = name; } public String toString() { return String.format("%s (age: %d)", new Object[] { this.name, Integer.valueOf(this.age) }); } public static void main(String[] args) { GetterSetterExample example = new GetterSetterExample(); example.setActive(true); example.setAge(123); example.setDate(new Date()); example.setName("abc"); example.setNone(Boolean.valueOf(false)); System.out.println(example); Date date = example.getDate(); Boolean none = example.getNone(); boolean active = example.isActive(); } }
虽然ToString在生产环境貌似没什么卵用。但是,很多情况下,我们还是需要这个的。因为记log。不想每次看log的时候是一串@地址,那就好好把toString()加上。
import lombok.Getter; import lombok.Setter; import lombok.ToString; @Setter @ToString(exclude = "id") public class ToStringExample { @Getter private static final int STATIC_VAR = 10; private String name; private Shape shape = new Square(5, 10); private String[] tags; @Getter private int id; @ToString(callSuper = true, includeFieldNames = true) public static class Square extends Shape { private final int width, height; public Square(int width, int height) { this.width = width; this.height = height; } } @ToString public static class Shape { private int color; } public static void main(String[] args) { final ToStringExample example = new ToStringExample(); example.setId(1); example.setName("abc"); example.setTags(new String[]{"a", "b", "c"}); final Shape shape = new Square(1, 2); example.setShape(shape); System.out.println(example.toString()); } }
ToString 一些需要注意的地方:
打印结果如下:
ToStringExample(name=abc, shape=ToStringExample.Square(super=ToStringExample.Shape(color=0), width=1, height=2), tags=[a, b, c])
编译后的代码如下:
import java.io.PrintStream; import java.util.Arrays; public class ToStringExample { private static final int STATIC_VAR = 10; private String name; public void setTags(String[] tags) { this.tags = tags; } public void setId(int id) { this.id = id; } public void setName(String name) { this.name = name; } public void setShape(Shape shape) { this.shape = shape; } public String toString() { return "ToStringExample(name=" + this.name + ", shape=" + this.shape + ", tags=" + Arrays.deepToString(this.tags) + ")"; } public static int getSTATIC_VAR() { return 10; } private Shape shape = new Square(5, 10); private String[] tags; private int id; public int getId() { return this.id; } public static class Square extends ToStringExample.Shape { private final int width; private final int height; public String toString() { return "ToStringExample.Square(super=" + super.toString() + ", width=" + this.width + ", height=" + this.height + ")"; } public Square(int width, int height) { this.width = width; this.height = height; } } public static class Shape { private int color; public String toString() { return "ToStringExample.Shape(color=" + this.color + ")"; } } public static void main(String[] args) { ToStringExample example = new ToStringExample(); example.setId(1); example.setName("abc"); example.setTags(new String[] { "a", "b", "c" }); Shape shape = new Square(1, 2); example.setShape(shape); System.out.println(example.toString()); } }
equals()和hashCode()在Java中有着举足轻重的基地作用,虽然通常很少关注。但是,这个必须不可省。不知道有几个可以手写出来的。
import com.sun.org.apache.xalan.internal.xsltc.compiler.sym; import lombok.EqualsAndHashCode; @EqualsAndHashCode(exclude = { "id", "shape" }) @SuppressWarnings("unused") public class EqualsAndHashCodeExample { private transient int transientVar = 10; private String name; private double score; private String[] tags; private int id; private ToStringExample.Shape shape = new Square(5, 10); @EqualsAndHashCode(callSuper=true) public static class Square extends ToStringExample.Shape { private final int width, height; public Square(int width, int height) { this.width = width; this.height = height; } } public static void main(String[] args) { EqualsAndHashCodeExample example = new EqualsAndHashCodeExample(); EqualsAndHashCodeExample example1 = new EqualsAndHashCodeExample(); boolean equals = example.equals(example1); System.out.println(equals); boolean b = example.canEqual(example); System.out.println(b); int i = example.hashCode(); System.out.println(i); } }
注意:
编译后的结果为:
import java.io.PrintStream; import java.util.Arrays; public class EqualsAndHashCodeExample { public int hashCode() { int PRIME = 59;int result = 1;Object $name = this.name;result = result * 59 + ($name == null ? 43 : $name.hashCode());long $score = Double.doubleToLongBits(this.score);result = result * 59 + (int)($score ^ $score >>> 32);result = result * 59 + Arrays.deepHashCode(this.tags);return result; } protected boolean canEqual(Object other) { return other instanceof EqualsAndHashCodeExample; } public boolean equals(Object o) { if (o == this) { return true; } if (!(o instanceof EqualsAndHashCodeExample)) { return false; } EqualsAndHashCodeExample other = (EqualsAndHashCodeExample)o; if (!other.canEqual(this)) { return false; } Object this$name = this.name;Object other$name = other.name; if (this$name == null ? other$name != null : !this$name.equals(other$name)) { return false; } if (Double.compare(this.score, other.score) != 0) { return false; } return Arrays.deepEquals(this.tags, other.tags); } private transient int transientVar = 10; private String name; private double score; private String[] tags; private int id; private ToStringExample.Shape shape = new Square(5, 10); public static class Square extends ToStringExample.Shape { private final int width; private final int height; public int hashCode() { int PRIME = 59;int result = super.hashCode();result = result * 59 + this.width;result = result * 59 + this.height;return result; } protected boolean canEqual(Object other) { return other instanceof Square; } public boolean equals(Object o) { if (o == this) { return true; } if (!(o instanceof Square)) { return false; } Square other = (Square)o; if (!other.canEqual(this)) { return false; } if (!super.equals(o)) { return false; } if (this.width != other.width) { return false; } return this.height == other.height; } public Square(int width, int height) { this.width = width; this.height = height; } } public static void main(String[] args) { EqualsAndHashCodeExample example = new EqualsAndHashCodeExample(); EqualsAndHashCodeExample example1 = new EqualsAndHashCodeExample(); boolean equals = example.equals(example1); System.out.println(equals); boolean b = example.canEqual(example); System.out.println(b); int i = example.hashCode(); System.out.println(i); } }
Java中class的一切起源于构造器。大家最喜欢的还是构造函数创建对象。这里有一点比较坑的是无参构造函数。当你自己添加一个带有参数的构造函数后,无参构造函数则被隐藏。通常也没啥问题,但当你使用jackson反序列化对象的时候就被恶心到了。jackson通过无参构造函数创建对象。因此,当你考虑这个class会用来序列化为json的时候,即必须手动添加一个无参数构造函数。
当你想要创建一个valueobject,DDD中的值对象,要求实现Immutable,那么无参数构造器就不合适了。@NoArgsConstructor会生成一个空的构造器。如果你设置了final field,那么编译会报错。如果你强制执行创建无参数构造器。即,@NoArgsConstructor(force = true),那么final的field会初始化为0/false/null。通常适合与@Data集成。
import lombok.NoArgsConstructor;
import lombok.NonNull;
@NoArgsConstructor(force=true)
public class NoArgsExample {
@NonNull
private final String field;
public static void main(String[] args) {
new NoArgsExample();
}
}
最终生成的代码如下:
import lombok.NonNull;
public class NoArgsExample
{
@NonNull
private final String field = null;
public static void main(String[] args)
{
new NoArgsExample();
}
}
对于final的字段,我认为我不会用空构造器来做这件事。所以,感觉这个参数force=true不要也罢,鸡肋。
一个class可以有很多属性,但你可能只关心其中的几个字段,那么可以使用@RequiredArgsConstructor。@NonNull将标注这个字段不应为null,初始化的时候会检查是否为空,否则抛出NullPointException。在上面的无参构造函数中被忽略了。那么,对于关注的字段标注@NonNull, @RequiredArgsConstructor则会生成带有这些字段的构造器。
import java.util.Date; import lombok.NonNull; import lombok.RequiredArgsConstructor; @RequiredArgsConstructor @SuppressWarnings("unused") public class RequiredArgsExample { @NonNull private String field; private Date date; private Integer integer; private int i; private boolean b; private Boolean aBoolean; }
最终生成结果:
import java.util.Date; import lombok.NonNull; public class RequiredArgsExample { @NonNull private String field; private Date date; private Integer integer; private int i; private boolean b; private Boolean aBoolean; public RequiredArgsExample(@NonNull String field) { if (field == null) { throw new NullPointerException("field is marked non-null but is null"); } this.field = field; } }
只有@NonNull会生成构造器。其他默认,Java的class初始化默认为null.false,0.
lombok提供了另一种初始化做法,静态初始化。即私有构造器,使用静态方法创建对象。这种做法看起来简单,但通常用的不多。因为静态初始化的东西很难mock,对测试不够友好。
import java.util.Date; import lombok.NonNull; import lombok.RequiredArgsConstructor; @SuppressWarnings("unused") @RequiredArgsConstructor(staticName="of") public class RequiredArgsStaticExample { @NonNull private String field; private Date date; private Integer integer; private int i; private boolean b; private Boolean aBoolean; }
最终生成代码如下:
import java.util.Date; import lombok.NonNull; public class RequiredArgsStaticExample { @NonNull private String field; private Date date; private Integer integer; private int i; private boolean b; private Boolean aBoolean; public static RequiredArgsStaticExample of(@NonNull String field) { return new RequiredArgsStaticExample(field); } private RequiredArgsStaticExample(@NonNull String field) { if (field == null) { throw new NullPointerException("field is marked non-null but is null"); } this.field = field; } }
想要初始化所有字段。
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.NonNull;
@AllArgsConstructor(access=AccessLevel.PROTECTED)
public class AllArgsConstructorExample<T> {
@SuppressWarnings("unused")
private int x, y;
@NonNull private T description;
}
最终生成代码如下:
import lombok.NonNull; public class AllArgsConstructorExample<T> { private int x; private int y; @NonNull private T description; protected AllArgsConstructorExample(int x, int y, @NonNull T description) { if (description == null) { throw new NullPointerException("description is marked non-null but is null"); } this.x = x;this.y = y;this.description = description; } }
@Data是一个集合体。包含Getter,Setter,RequiredArgsConstructor,ToString,EqualsAndHashCode
import lombok.AccessLevel; import lombok.Data; import lombok.Setter; import lombok.ToString; @Data public class DataExample { private final String name; @Setter(AccessLevel.PACKAGE) private int age; private double score; private String[] tags; @ToString(includeFieldNames=true) @Data(staticConstructor="of") public static class Exercise<T> { private final String name; private final T valueT; } }
最终生成代码如下:
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 toString() { return "DataExample(name=" + getName() + ", age=" + getAge() + ", score=" + getScore() + ", tags=" + Arrays.deepToString(getTags()) + ")"; } public int hashCode() { int PRIME = 59;int result = 1;Object $name = getName();result = result * 59 + ($name == null ? 43 : $name.hashCode());result = result * 59 + getAge();long $score = Double.doubleToLongBits(getScore());result = result * 59 + (int)($score ^ $score >>> 32);result = result * 59 + Arrays.deepHashCode(getTags());return result; } protected boolean canEqual(Object other) { return other instanceof DataExample; } public boolean equals(Object o) { if (o == this) { return true; } if (!(o instanceof DataExample)) { return false; } DataExample other = (DataExample)o; if (!other.canEqual(this)) { return false; } Object this$name = getName();Object other$name = other.getName(); if (this$name == null ? other$name != null : !this$name.equals(other$name)) { return false; } if (getAge() != other.getAge()) { return false; } if (Double.compare(getScore(), other.getScore()) != 0) { return false; } return Arrays.deepEquals(getTags(), other.getTags()); } public void setTags(String[] tags) { this.tags = tags; } public void setScore(double score) { this.score = score; } public String[] getTags() { return this.tags; } public double getScore() { return this.score; } public int getAge() { return this.age; } public String getName() { return this.name; } void setAge(int age) { this.age = age; } public static class Exercise<T> { private final String name; private final T valueT; public String toString() { return "DataExample.Exercise(name=" + getName() + ", valueT=" + getValueT() + ")"; } public String getName() { return this.name; } public T getValueT() { return this.valueT; } public boolean equals(Object o) { if (o == this) { return true; } if (!(o instanceof Exercise)) { return false; } Exercise<?> other = (Exercise)o; if (!other.canEqual(this)) { return false; } Object this$name = getName();Object other$name = other.getName(); if (this$name == null ? other$name != null : !this$name.equals(other$name)) { return false; } Object this$valueT = getValueT();Object other$valueT = other.getValueT();return this$valueT == null ? other$valueT == null : this$valueT.equals(other$valueT); } protected boolean canEqual(Object other) { return other instanceof Exercise; } public int hashCode() { int PRIME = 59;int result = 1;Object $name = getName();result = result * 59 + ($name == null ? 43 : $name.hashCode());Object $valueT = getValueT();result = result * 59 + ($valueT == null ? 43 : $valueT.hashCode());return result; } private Exercise(String name, T valueT) { this.name = name;this.valueT = valueT; } public static <T> Exercise<T> of(String name, T valueT) { return new Exercise(name, valueT); } } }
这个看起来很美好,就是可以帮忙生成一个不可变对象。对于所有的字段都将生成final的。但我感觉有点失控。注解的优势应该是所见即所得,可以通过字面量来传递消息。而@Value字段给字段加final会让人困惑,因为这更改了我们的定义。当我想声明一个Immutable对象的时候,我会显示的给字段加一个限定final。
同@Data, @Value是一个集合体。包含Getter,AllArgsConstructor,ToString,EqualsAndHashCode。
import java.util.Date;
import lombok.NonNull;
import lombok.Value;
@Value
public class ValueExample {
@NonNull
private String id;
private String name;
private boolean active;
private Date createTime;
}
编译后
import java.util.Date; import lombok.NonNull; public final class ValueExample { @NonNull private final String id; private final String name; private final boolean active; private final Date createTime; public ValueExample(@NonNull String id, String name, boolean active, Date createTime) { if (id == null) { throw new NullPointerException("id is marked non-null but is null"); } this.id = id;this.name = name;this.active = active;this.createTime = createTime; } public String toString() { return "ValueExample(id=" + getId() + ", name=" + getName() + ", active=" + isActive() + ", createTime=" + getCreateTime() + ")"; } public int hashCode() { int PRIME = 59;int result = 1;Object $id = getId();result = result * 59 + ($id == null ? 43 : $id.hashCode());Object $name = getName();result = result * 59 + ($name == null ? 43 : $name.hashCode());result = result * 59 + (isActive() ? 79 : 97);Object $createTime = getCreateTime();result = result * 59 + ($createTime == null ? 43 : $createTime.hashCode());return result; } public boolean equals(Object o) { if (o == this) { return true; } if (!(o instanceof ValueExample)) { return false; } ValueExample other = (ValueExample)o;Object this$id = getId();Object other$id = other.getId(); if (this$id == null ? other$id != null : !this$id.equals(other$id)) { return false; } Object this$name = getName();Object other$name = other.getName(); if (this$name == null ? other$name != null : !this$name.equals(other$name)) { return false; } if (isActive() != other.isActive()) { return false; } Object this$createTime = getCreateTime();Object other$createTime = other.getCreateTime();return this$createTime == null ? other$createTime == null : this$createTime.equals(other$createTime); } public Date getCreateTime() { return this.createTime; } public boolean isActive() { return this.active; } public String getName() { return this.name; } @NonNull public String getId() { return this.id; } }
对于喜欢builder模式的人来说,声明式简化对象创建流程让一切看得美好。但是,手动复制字段,手动创建方法很让人不喜。@Builder解决了刚需。
import java.util.Date; import java.util.Set; import org.junit.Assert; import lombok.Builder; import lombok.Data; import lombok.NonNull; import lombok.Singular; @Data @Builder(toBuilder = true) public class BuilderExample { @NonNull private String id; private String name; private boolean active; private Date createTime; @Singular private Set<String> occupations; public static void main(String[] args) { BuilderExample builer = BuilderExample.builder().active(true) .name("name") .id("id") .createTime(new Date()) .occupation("1") .occupation("2") .build(); Assert.assertEquals(2, builer.getOccupations().size()); } }
这才是我们想要的建造者。对应生成的代码为:
import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.LinkedHashSet; import java.util.Set; import lombok.NonNull; import org.junit.Assert; public class BuilderExample { @NonNull private String id; private String name; private boolean active; private Date createTime; private Set<String> occupations; public String toString() { return "BuilderExample(id=" + getId() + ", name=" + getName() + ", active=" + isActive() + ", createTime=" + getCreateTime() + ", occupations=" + getOccupations() + ")"; } public int hashCode() { int PRIME = 59;int result = 1;Object $id = getId();result = result * 59 + ($id == null ? 43 : $id.hashCode());Object $name = getName();result = result * 59 + ($name == null ? 43 : $name.hashCode());result = result * 59 + (isActive() ? 79 : 97);Object $createTime = getCreateTime();result = result * 59 + ($createTime == null ? 43 : $createTime.hashCode());Object $occupations = getOccupations();result = result * 59 + ($occupations == null ? 43 : $occupations.hashCode());return result; } protected boolean canEqual(Object other) { return other instanceof BuilderExample; } public boolean equals(Object o) { if (o == this) { return true; } if (!(o instanceof BuilderExample)) { return false; } BuilderExample other = (BuilderExample)o; if (!other.canEqual(this)) { return false; } Object this$id = getId();Object other$id = other.getId(); if (this$id == null ? other$id != null : !this$id.equals(other$id)) { return false; } Object this$name = getName();Object other$name = other.getName(); if (this$name == null ? other$name != null : !this$name.equals(other$name)) { return false; } if (isActive() != other.isActive()) { return false; } Object this$createTime = getCreateTime();Object other$createTime = other.getCreateTime(); if (this$createTime == null ? other$createTime != null : !this$createTime.equals(other$createTime)) { return false; } Object this$occupations = getOccupations();Object other$occupations = other.getOccupations();return this$occupations == null ? other$occupations == null : this$occupations.equals(other$occupations); } public void setOccupations(Set<String> occupations) { this.occupations = occupations; } public void setCreateTime(Date createTime) { this.createTime = createTime; } public void setActive(boolean active) { this.active = active; } public void setName(String name) { this.name = name; } public void setId(@NonNull String id) { if (id == null) { throw new NullPointerException("id is marked non-null but is null"); } this.id = id; } public Set<String> getOccupations() { return this.occupations; } public Date getCreateTime() { return this.createTime; } public boolean isActive() { return this.active; } public String getName() { return this.name; } @NonNull public String getId() { return this.id; } public static class BuilderExampleBuilder { private String id; private String name; private boolean active; private Date createTime; private ArrayList<String> occupations; public String toString() { return "BuilderExample.BuilderExampleBuilder(id=" + this.id + ", name=" + this.name + ", active=" + this.active + ", createTime=" + this.createTime + ", occupations=" + this.occupations + ")"; } public BuilderExample build() { Set<String> occupations; Set<String> occupations; Set<String> occupations; switch (this.occupations == null ? 0 : this.occupations.size()) { case 0: occupations = Collections.emptySet(); break; case 1: occupations = Collections.singleton((String)this.occupations.get(0)); break; default: occupations = new LinkedHashSet(this.occupations.size() < 1073741824 ? 1 + this.occupations.size() + (this.occupations.size() - 3) / 3 : 2147483647);occupations.addAll(this.occupations);occupations = Collections.unmodifiableSet(occupations); } return new BuilderExample(this.id, this.name, this.active, this.createTime, occupations); } public BuilderExampleBuilder clearOccupations() { if (this.occupations != null) { this.occupations.clear(); } return this; } public BuilderExampleBuilder occupations(Collection<? extends String> occupations) { if (this.occupations == null) { this.occupations = new ArrayList(); } this.occupations.addAll(occupations);return this; } public BuilderExampleBuilder occupation(String occupation) { if (this.occupations == null) { this.occupations = new ArrayList(); } this.occupations.add(occupation);return this; } public BuilderExampleBuilder createTime(Date createTime) { this.createTime = createTime;return this; } public BuilderExampleBuilder active(boolean active) { this.active = active;return this; } public BuilderExampleBuilder name(String name) { this.name = name;return this; } public BuilderExampleBuilder id(@NonNull String id) { if (id == null) { throw new NullPointerException("id is marked non-null but is null"); } this.id = id;return this; } } public BuilderExampleBuilder toBuilder() { BuilderExampleBuilder builder = new BuilderExampleBuilder().id(this.id).name(this.name).active(this.active).createTime(this.createTime); if (this.occupations != null) { builder.occupations(this.occupations); } return builder; } public static BuilderExampleBuilder builder() { return new BuilderExampleBuilder(); } BuilderExample(@NonNull String id, String name, boolean active, Date createTime, Set<String> occupations) { if (id == null) { throw new NullPointerException("id is marked non-null but is null"); } this.id = id;this.name = name;this.active = active;this.createTime = createTime;this.occupations = occupations; } public static void main(String[] args) { BuilderExample builer = builder().active(true) .name("name") .id("id") .createTime(new Date()) .occupation("1") .occupation("2") .build(); Assert.assertEquals(2L, builer.getOccupations().size()); } }
日志相关的注解。这里以 @Slf4j 为例。
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class LogExample {
public static void main(String[] args) {
log.error("Something else is wrong here");
}
}
这里需要添加 slf4j 以及它的实现类的依赖
<!-- @Slf4j 支持 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
编译后
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class LogExample
{
private static final Logger log = LoggerFactory.getLogger(LogExample.class);
public static void main(String[] args)
{
log.error("Something else is wrong here");
}
}
可以使用 val 声明本地变量的类型而不用写出它的实际类型,它实际的类型将由初始化的表达式推断。
import java.util.HashMap; import lombok.val; public class ValExample { public static void main(String[] args) { // lombok.val 使用 val map = new HashMap<Integer, String>(); map.put(0, "zero"); map.put(5, "five"); for(val entry : map.entrySet()) { System.out.println(entry.getKey() + ":" + entry.getValue()); } } }
编译后
import java.io.PrintStream; import java.util.HashMap; import java.util.Map.Entry; public class ValExample { public static void main(String[] args) { HashMap<Integer, String> map = new HashMap(); map.put(Integer.valueOf(0), "zero"); map.put(Integer.valueOf(5), "five"); for (Map.Entry<Integer, String> entry : map.entrySet()) { System.out.println(entry.getKey() + ":" + (String)entry.getValue()); } } }
lombok还提供了其他几个注解,以及还有好多内置的参数没有讲解。但是,根据2-8原理,我们根本不需要。上面这几个足够了。更多的注解只会增加理解阅读难度。
会发现在Lombok使用的过程中,只需要添加相应的注解,无需再为此写任何代码。自动生成的代码到底是如何产生的呢?
核心之处就是对于注解的解析上。JDK5引入了注解的同时,也提供了两种解析方式。
运行时解析
运行时能够解析的注解,必须将@Retention设置为RUNTIME,这样就可以通过反射拿到该注解。java.lang,reflect反射包中提供了一个接口AnnotatedElement,该接口定义了获取注解信息的几个方法,Class、Constructor、Field、Method、Package等都实现了该接口,对反射熟悉的朋友应该都会很熟悉这种解析方式。
编译时解析
编译时解析有两种机制,分别简单描述下:
1)Annotation Processing Tool
apt自JDK5产生,JDK7已标记为过期,不推荐使用,JDK8中已彻底删除,自JDK6开始,可以使用Pluggable Annotation Processing API来替换它,apt被替换主要有2点原因:
2)Pluggable Annotation Processing API
JSR 269自JDK6加入,作为apt的替代方案,它解决了apt的两个问题,javac在执行的时候会调用实现了该API的程序,这样我们就可以对编译器做一些增强,这时javac执行的过程如下:
Lombok本质上就是一个实现了“JSR 269 API”的程序。在使用javac的过程中,它产生作用的具体流程如下:
拜读了Lombok源码,对应注解的实现都在HandleXXX中,比如@Getter注解的实现时HandleGetter.handle()。还有一些其它类库使用这种方式实现,比如Google Auto、Dagger等等。
优点:
缺点:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。