Lombok 是一款 Java 开发插件,使得 Java 开发者能够经过其定义的一些注解来消除业务工程中冗长和繁琐的代码,尤为对于简单的 Java 模型对象(POJO)。在开发环境中使用 Lombok 插件后,Java 开发人员能够节省出重复构建,诸如 hashCode 和 equals 这样的方法以及各类业务对象模型的 accessor 和 toString 等方法的大量时间。对于这些方法,Lombok 可以在编译源代码期间自动帮咱们生成这些方法,但并不会像反射那样下降程序的性能。html
在 Maven 项目的 pom.xml 文件中添加 Lombok 依赖:java
<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.10</version> <scope>provided</scope> </dependency>
在 build.gradle 文件中添加 Lombok 依赖:apache
dependencies { compileOnly 'org.projectlombok:lombok:1.18.10' annotationProcessor 'org.projectlombok:lombok:1.18.10' }
假设在 lib 目录中已经存在 lombok.jar,而后设置 javac 任务:segmentfault
<javac srcdir="src" destdir="build" source="1.8"> <classpath location="lib/lombok.jar" /> </javac>
因为 Lombok 仅在编译阶段生成代码,因此使用 Lombok 注解的源代码,在 IDE 中会被高亮显示错误,针对这个问题能够经过安装 IDE 对应的插件来解决。具体的安装方式能够参考:https://www.baeldung.com/lombok-ide。安全
Lombok in IntelliJ IDEA微信
Lombok in Eclipseeclipse
注解说明ide
val
:用在局部变量前面,至关于将变量声明为final@NonNull
:给方法参数增长这个注解会自动在方法内对该参数进行是否为空的校验,若是为空,则抛出NPE(NullPointerException)@Cleanup
:自动管理资源,用在局部变量以前,在当前变量范围内即将执行完毕退出以前会自动清理资源,自动生成try-finally这样的代码来关闭流@Getter/@Setter
:用在属性上,不再用本身手写setter和getter方法了,还能够指定访问范围@ToString
:用在类上,能够自动覆写toString方法,固然还能够加其余参数,例如@ToString(exclude=”id”)排除id属性,或者@ToString(callSuper=true, includeFieldNames=true)调用父类的toString方法,包含全部属性@EqualsAndHashCode
:用在类上,自动生成equals方法和hashCode方法@NoArgsConstructor, @RequiredArgsConstructor and @AllArgsConstructor
:用在类上,自动生成无参构造和使用全部参数的构造函数以及把全部@NonNull属性做为参数的构造函数,若是指定staticName = “of”参数,同时还会生成一个返回类对象的静态工厂方法,比使用构造函数方便不少@Data
:注解在类上,至关于同时使用了@ToString
、@EqualsAndHashCode
、@Getter
、@Setter
和@RequiredArgsConstrutor
这些注解,对于POJO类
十分有用@Value
:用在类上,是@Data的不可变形式,至关于为属性添加final声明,只提供getter方法,而不提供setter方法@Builder
:用在类、构造器、方法上,为你提供复杂的builder APIs,让你能够像以下方式同样调用Person.builder().name("Adam Savage").city("San Francisco").job("Mythbusters").job("Unchained Reaction").build();
更多说明参考Builder@SneakyThrows
:自动抛受检异常,而无需显式在方法上使用throws语句@Synchronized
:用在方法上,将方法声明为同步的,并自动加锁,而锁对象是一个私有的属性$lock
或$LOCK
,而java中的synchronized关键字锁对象是this,锁在this或者本身的类对象上存在反作用,就是你不能阻止非受控代码去锁this或者类对象,这可能会致使竞争条件或者其它线程错误@Getter(lazy=true)
:能够替代经典的Double Check Lock样板代码@Log
:根据不一样的注解生成不一样类型的log对象,可是实例名称都是log,有六种可选实现类
@CommonsLog
Creates log = org.apache.commons.logging.LogFactory.getLog(LogExample.class);@Log
Creates log = java.util.logging.Logger.getLogger(LogExample.class.getName());@Log4j
Creates log = org.apache.log4j.Logger.getLogger(LogExample.class);@Log4j2
Creates log = org.apache.logging.log4j.LogManager.getLogger(LogExample.class);@Slf4j
Creates log = org.slf4j.LoggerFactory.getLogger(LogExample.class);@XSlf4j
Creates log = org.slf4j.ext.XLoggerFactory.getXLogger(LogExample.class);你可使用 @Getter
或 @Setter
注释任何类或字段,Lombok 会自动生成默认的 getter/setter
方法。函数
@Getter工具
@Target({ElementType.FIELD, ElementType.TYPE}) @Retention(RetentionPolicy.SOURCE) public @interface Getter { // 若getter方法非public的话,能够设置可访问级别 lombok.AccessLevel value() default lombok.AccessLevel.PUBLIC; AnyAnnotation[] onMethod() default {}; // 是否启用延迟初始化 boolean lazy() default false; }
@Setter
@Target({ElementType.FIELD, ElementType.TYPE}) @Retention(RetentionPolicy.SOURCE) public @interface Setter { // 若setter方法非public的话,能够设置可访问级别 lombok.AccessLevel value() default lombok.AccessLevel.PUBLIC; AnyAnnotation[] onMethod() default {}; AnyAnnotation[] onParam() default {}; }
使用示例
@Getter @Setter public class GetterAndSetterDemo { String firstName; String lastName; LocalDate dateOfBirth; }
以上代码通过 Lombok 编译后,会生成以下代码:
public class GetterAndSetterDemo { String firstName; String lastName; LocalDate dateOfBirth; public GetterAndSetterDemo() { } // 省略其它setter和getter方法 public String getFirstName() { return this.firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } }
Lazy Getter
@Getter 注解支持一个 lazy 属性,该属性默认为 false。当设置为 true 时,会启用延迟初始化,即当首次调用 getter 方法时才进行初始化。
示例
public class LazyGetterDemo { public static void main(String[] args) { LazyGetterDemo m = new LazyGetterDemo(); System.out.println("Main instance is created"); m.getLazy(); } @Getter private final String notLazy = createValue("not lazy"); @Getter(lazy = true) private final String lazy = createValue("lazy"); private String createValue(String name) { System.out.println("createValue(" + name + ")"); return null; } }
以上代码通过 Lombok 编译后,会生成以下代码:
public class LazyGetterDemo { private final String notLazy = this.createValue("not lazy"); private final AtomicReference<Object> lazy = new AtomicReference(); // 已省略部分代码 public String getNotLazy() { return this.notLazy; } public String getLazy() { Object value = this.lazy.get(); if (value == null) { synchronized(this.lazy) { value = this.lazy.get(); if (value == null) { String actualValue = this.createValue("lazy"); value = actualValue == null ? this.lazy : actualValue; this.lazy.set(value); } } } return (String)((String)(value == this.lazy ? null : value)); } }
经过以上代码可知,调用 getLazy 方法时,若发现 value 为 null,则会在同步代码块中执行初始化操做。
@NoArgsConstructor
使用 @NoArgsConstructor 注解能够为指定类,生成默认的构造函数,@NoArgsConstructor 注解的定义以下:
@Target(ElementType.TYPE) @Retention(RetentionPolicy.SOURCE) public @interface NoArgsConstructor { // 若设置该属性,将会生成一个私有的构造函数且生成一个staticName指定的静态方法 String staticName() default ""; AnyAnnotation[] onConstructor() default {}; // 设置生成构造函数的访问级别,默认是public AccessLevel access() default lombok.AccessLevel.PUBLIC; // 若设置为true,则初始化全部final的字段为0/null/false boolean force() default false; }
示例
@NoArgsConstructor(staticName = "getInstance") public class NoArgsConstructorDemo { private long id; private String name; private int age; }
以上代码通过 Lombok 编译后,会生成以下代码:
public class NoArgsConstructorDemo { private long id; private String name; private int age; private NoArgsConstructorDemo() { } public static NoArgsConstructorDemo getInstance() { return new NoArgsConstructorDemo(); } }
@AllArgsConstructor
使用 @AllArgsConstructor 注解能够为指定类,生成包含全部成员的构造函数,@AllArgsConstructor 注解的定义以下:
@Target(ElementType.TYPE) @Retention(RetentionPolicy.SOURCE) public @interface AllArgsConstructor { // 若设置该属性,将会生成一个私有的构造函数且生成一个staticName指定的静态方法 String staticName() default ""; AnyAnnotation[] onConstructor() default {}; // 设置生成构造函数的访问级别,默认是public AccessLevel access() default lombok.AccessLevel.PUBLIC; }
示例
@AllArgsConstructor public class AllArgsConstructorDemo { private long id; private String name; private int age; }
以上代码通过 Lombok 编译后,会生成以下代码:
public class AllArgsConstructorDemo { private long id; private String name; private int age; public AllArgsConstructorDemo(long id, String name, int age) { this.id = id; this.name = name; this.age = age; } }
@RequiredArgsConstructor
使用 @RequiredArgsConstructor 注解能够为指定类必需初始化的成员变量,如 final 成员变量,生成对应的构造函数,@RequiredArgsConstructor 注解的定义以下:
@Target(ElementType.TYPE) @Retention(RetentionPolicy.SOURCE) public @interface RequiredArgsConstructor { // 若设置该属性,将会生成一个私有的构造函数且生成一个staticName指定的静态方法 String staticName() default ""; AnyAnnotation[] onConstructor() default {}; // 设置生成构造函数的访问级别,默认是public AccessLevel access() default lombok.AccessLevel.PUBLIC; }
示例
@RequiredArgsConstructor public class RequiredArgsConstructorDemo { private final long id; private String name; private int age; }
以上代码通过 Lombok 编译后,会生成以下代码:
public class RequiredArgsConstructorDemo { private final long id; private String name; private int age; public RequiredArgsConstructorDemo(long id) { this.id = id; } }
使用 @EqualsAndHashCode 注解能够为指定类生成 equals 和 hashCode 方法, @EqualsAndHashCode 注解的定义以下:
@Target(ElementType.TYPE) @Retention(RetentionPolicy.SOURCE) public @interface EqualsAndHashCode { // 指定在生成的equals和hashCode方法中须要排除的字段列表 String[] exclude() default {}; // 显式列出用于identity的字段,通常状况下non-static,non-transient字段会被用于identity String[] of() default {}; // 标识在执行字段计算前,是否调用父类的equals和hashCode方法 boolean callSuper() default false; boolean doNotUseGetters() default false; AnyAnnotation[] onParam() default {}; @Deprecated @Retention(RetentionPolicy.SOURCE) @Target({}) @interface AnyAnnotation {} @Target(ElementType.FIELD) @Retention(RetentionPolicy.SOURCE) public @interface Exclude {} @Target({ElementType.FIELD, ElementType.METHOD}) @Retention(RetentionPolicy.SOURCE) public @interface Include { String replaces() default ""; } }
示例
@EqualsAndHashCode public class EqualsAndHashCodeDemo { String firstName; String lastName; LocalDate dateOfBirth; }
以上代码通过 Lombok 编译后,会生成以下代码:
public class EqualsAndHashCodeDemo { String firstName; String lastName; LocalDate dateOfBirth; public EqualsAndHashCodeDemo() { } public boolean equals(Object o) { if (o == this) { return true; } else if (!(o instanceof EqualsAndHashCodeDemo)) { return false; } else { EqualsAndHashCodeDemo other = (EqualsAndHashCodeDemo)o; if (!other.canEqual(this)) { return false; } else { // 已省略大量代码 } } public int hashCode() { int PRIME = true; int result = 1; Object $firstName = this.firstName; int result = result * 59 + ($firstName == null ? 43 : $firstName.hashCode()); Object $lastName = this.lastName; result = result * 59 + ($lastName == null ? 43 : $lastName.hashCode()); Object $dateOfBirth = this.dateOfBirth; result = result * 59 + ($dateOfBirth == null ? 43 : $dateOfBirth.hashCode()); return result; } }
使用 @ToString 注解能够为指定类生成 toString 方法, @ToString 注解的定义以下:
@Target(ElementType.TYPE) @Retention(RetentionPolicy.SOURCE) public @interface ToString { // 打印输出时是否包含字段的名称 boolean includeFieldNames() default true; // 列出打印输出时,须要排除的字段列表 String[] exclude() default {}; // 显式的列出须要打印输出的字段列表 String[] of() default {}; // 打印输出的结果中是否包含父类的toString方法的返回结果 boolean callSuper() default false; boolean doNotUseGetters() default false; boolean onlyExplicitlyIncluded() default false; @Target(ElementType.FIELD) @Retention(RetentionPolicy.SOURCE) public @interface Exclude {} @Target({ElementType.FIELD, ElementType.METHOD}) @Retention(RetentionPolicy.SOURCE) public @interface Include { int rank() default 0; String name() default ""; } }
示例
@ToString(exclude = {"dateOfBirth"}) public class ToStringDemo { String firstName; String lastName; LocalDate dateOfBirth; }
以上代码通过 Lombok 编译后,会生成以下代码:
public class ToStringDemo { String firstName; String lastName; LocalDate dateOfBirth; public ToStringDemo() { } public String toString() { return "ToStringDemo(firstName=" + this.firstName + ", lastName=" + this.lastName + ")"; } }
@Data 注解与同时使用如下的注解的效果是同样的:
@ToString
@Getter
@Setter
@RequiredArgsConstructor
@EqualsAndHashCode
@Data 注解的定义以下:
@Target(ElementType.TYPE) @Retention(RetentionPolicy.SOURCE) public @interface Data { String staticConstructor() default ""; }
示例
@Data public class DataDemo { private Long id; private String summary; private String description; }
以上代码通过 Lombok 编译后,会生成以下代码:
public class DataDemo { private Long id; private String summary; private String description; public DataDemo() { } // 省略summary和description成员属性的setter和getter方法 public Long getId() { return this.id; } public void setId(Long id) { this.id = id; } public boolean equals(Object o) { if (o == this) { return true; } else if (!(o instanceof DataDemo)) { return false; } else { DataDemo other = (DataDemo)o; if (!other.canEqual(this)) { return false; } else { // 已省略大量代码 } } } protected boolean canEqual(Object other) { return other instanceof DataDemo; } public int hashCode() { int PRIME = true; int result = 1; Object $id = this.getId(); int result = result * 59 + ($id == null ? 43 : $id.hashCode()); Object $summary = this.getSummary(); result = result * 59 + ($summary == null ? 43 : $summary.hashCode()); Object $description = this.getDescription(); result = result * 59 + ($description == null ? 43 : $description.hashCode()); return result; } public String toString() { return "DataDemo(id=" + this.getId() + ", summary=" + this.getSummary() + ", description=" + this.getDescription() + ")"; } }
若你将 @Log 的变体放在类上(适用于你所使用的日志记录系统的任何一种);以后,你将拥有一个静态的 final log 字段,而后你就可使用该字段来输出日志。
@Log private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(LogExample.class.getName()); @Log4j private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(LogExample.class); @Log4j2 private static final org.apache.logging.log4j.Logger log = org.apache.logging.log4j.LogManager.getLogger(LogExample.class); @Slf4j private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LogExample.class); @XSlf4j private static final org.slf4j.ext.XLogger log = org.slf4j.ext.XLoggerFactory.getXLogger(LogExample.class); @CommonsLog private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(LogExample.class);
@Synchronized 是同步方法修饰符的更安全的变体。与 synchronized 同样,该注解只能应用在静态和实例方法上。它的操做相似于 synchronized 关键字,可是它锁定在不一样的对象上。synchronized 关键字应用在实例方法时,锁定的是 this 对象,而应用在静态方法上锁定的是类对象。对于 @Synchronized 注解声明的方法来讲,它锁定的是
或lock。@Synchronized 注解的定义以下:
@Target(ElementType.METHOD) @Retention(RetentionPolicy.SOURCE) public @interface Synchronized { // 指定锁定的字段名称 String value() default ""; }
示例
public class SynchronizedDemo { 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"); } }
以上代码通过 Lombok 编译后,会生成以下代码:
public class SynchronizedDemo { private static final Object $LOCK = new Object[0]; private final Object $lock = new Object[0]; private final Object readLock = new Object(); public SynchronizedDemo() { } public static void hello() { synchronized($LOCK) { System.out.println("world"); } } public int answerToLife() { synchronized(this.$lock) { return 42; } } public void foo() { synchronized(this.readLock) { System.out.println("bar"); } } }
使用 @Builder 注解能够为指定类实现建造者模式,该注解能够放在类、构造函数或方法上。@Builder 注解的定义以下:
@Target({TYPE, METHOD, CONSTRUCTOR}) @Retention(SOURCE) public @interface Builder { @Target(FIELD) @Retention(SOURCE) public @interface Default {} // 建立新的builder实例的方法名称 String builderMethodName() default "builder"; // 建立Builder注解类对应实例的方法名称 String buildMethodName() default "build"; // builder类的名称 String builderClassName() default ""; boolean toBuilder() default false; AccessLevel access() default lombok.AccessLevel.PUBLIC; @Target({FIELD, PARAMETER}) @Retention(SOURCE) public @interface ObtainVia { String field() default ""; String method() default ""; boolean isStatic() default false; } }
示例
@Builder public class BuilderDemo { private final String firstname; private final String lastname; private final String email; }
以上代码通过 Lombok 编译后,会生成以下代码:
public class BuilderDemo { private final String firstname; private final String lastname; private final String email; BuilderDemo(String firstname, String lastname, String email) { this.firstname = firstname; this.lastname = lastname; this.email = email; } public static BuilderDemo.BuilderDemoBuilder builder() { return new BuilderDemo.BuilderDemoBuilder(); } public static class BuilderDemoBuilder { private String firstname; private String lastname; private String email; BuilderDemoBuilder() { } public BuilderDemo.BuilderDemoBuilder firstname(String firstname) { this.firstname = firstname; return this; } public BuilderDemo.BuilderDemoBuilder lastname(String lastname) { this.lastname = lastname; return this; } public BuilderDemo.BuilderDemoBuilder email(String email) { this.email = email; return this; } public BuilderDemo build() { return new BuilderDemo(this.firstname, this.lastname, this.email); } public String toString() { return "BuilderDemo.BuilderDemoBuilder(firstname=" + this.firstname + ", lastname=" + this.lastname + ", email=" + this.email + ")"; } } }
@SneakyThrows 注解用于自动抛出已检查的异常,而无需在方法中使用 throw 语句显式抛出。@SneakyThrows 注解的定义以下:
@Target({ElementType.METHOD, ElementType.CONSTRUCTOR}) @Retention(RetentionPolicy.SOURCE) public @interface SneakyThrows { // 设置你但愿向上抛的异常类 Class<? extends Throwable>[] value() default java.lang.Throwable.class; }
示例
public class SneakyThrowsDemo { @SneakyThrows @Override protected Object clone() { return super.clone(); } }
以上代码通过 Lombok 编译后,会生成以下代码:
public class SneakyThrowsDemo { public SneakyThrowsDemo() { } protected Object clone() { try { return super.clone(); } catch (Throwable var2) { throw var2; } } }
你能够在方法或构造函数的参数上使用 @NonNull 注解,它将会为你自动生成非空校验语句。@NonNull 注解的定义以下:
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.LOCAL_VARIABLE, ElementType.TYPE_USE}) @Retention(RetentionPolicy.CLASS) @Documented public @interface NonNull {
}
示例
public class NonNullDemo { @Getter @Setter @NonNull private String name; }
以上代码通过 Lombok 编译后,会生成以下代码:
public class NonNullDemo { @NonNull private String name; public NonNullDemo() { } @NonNull public String getName() { return this.name; } public void setName(@NonNull String name) { if (name == null) { throw new NullPointerException("name is marked non-null but is null"); } else { this.name = name; } } }
@Clean 注解用于自动管理资源,用在局部变量以前,在当前变量范围内即将执行完毕退出以前会自动清理资源,自动生成 try-finally 这样的代码来关闭流。
@Target(ElementType.LOCAL_VARIABLE) @Retention(RetentionPolicy.SOURCE) public @interface Cleanup { // 设置用于执行资源清理/回收的方法名称,对应方法不能包含任何参数,默认名称为close。 String value() default "close"; }
示例
public class CleanupDemo { public static void main(String[] args) throws IOException { @Cleanup InputStream in = new FileInputStream(args[0]); @Cleanup OutputStream out = new FileOutputStream(args[1]); byte[] b = new byte[10000]; while (true) { int r = in.read(b); if (r == -1) break; out.write(b, 0, r); } } }
以上代码通过 Lombok 编译后,会生成以下代码:
public class CleanupDemo { public CleanupDemo() { } public static void main(String[] args) throws IOException { FileInputStream in = new FileInputStream(args[0]); try { FileOutputStream out = new FileOutputStream(args[1]); try { byte[] b = new byte[10000]; while(true) { int r = in.read(b); if (r == -1) { return; } out.write(b, 0, r); } } finally { if (Collections.singletonList(out).get(0) != null) { out.close(); } } } finally { if (Collections.singletonList(in).get(0) != null) { in.close(); } } } }
在类的字段上应用 @With 注解以后,将会自动生成一个 withFieldName(newValue) 的方法,该方法会基于 newValue 调用相应构造函数,建立一个当前类对应的实例。@With 注解的定义以下:
@Target({ElementType.FIELD, ElementType.TYPE}) @Retention(RetentionPolicy.SOURCE) public @interface With { AccessLevel value() default AccessLevel.PUBLIC; With.AnyAnnotation[] onMethod() default {}; With.AnyAnnotation[] onParam() default {}; @Deprecated @Retention(RetentionPolicy.SOURCE) @Target({}) public @interface AnyAnnotation { } }
示例
public class WithDemo { @With(AccessLevel.PROTECTED) @NonNull private final String name; @With private final int age; public WithDemo(String name, int age) { if (name == null) throw new NullPointerException(); this.name = name; this.age = age; } }
以上代码通过 Lombok 编译后,会生成以下代码:
public class WithDemo { @NonNull private final String name; private final int age; public WithDemo(String name, int age) { if (name == null) { throw new NullPointerException(); } else { this.name = name; this.age = age; } } protected WithDemo withName(@NonNull String name) { if (name == null) { throw new NullPointerException("name is marked non-null but is null"); } else { return this.name == name ? this : new WithDemo(name, this.age); } } public WithDemo withAge(int age) { return this.age == age ? this : new WithDemo(this.name, age); } }
val
val 用在局部变量前面,至关于将变量声明为 final,此外 Lombok 在编译时还会自动进行类型推断。val 的使用示例:
public class ValExample { public String example() { val example = new ArrayList<String>(); example.add("Hello, World!"); val foo = example.get(0); return foo.toLowerCase(); } public void example2() { val map = new HashMap<Integer, String>(); map.put(0, "zero"); map.put(5, "five"); for (val entry : map.entrySet()) { System.out.printf("%d: %s\n", entry.getKey(), entry.getValue()); } } }
以上代码等价于:
public class ValExample { public String example() { final ArrayList<String> example = new ArrayList<String>(); example.add("Hello, World!"); final String foo = example.get(0); return foo.toLowerCase(); } public void example2() { final HashMap<Integer, String> map = new HashMap<Integer, String>(); map.put(0, "zero"); map.put(5, "five"); for (final Map.Entry<Integer, String> entry : map.entrySet()) { System.out.printf("%d: %s\n", entry.getKey(), entry.getValue()); } } }
说到 Lombok,咱们就得去提到 JSR 269: Pluggable Annotation Processing API (https://www.jcp.org/en/jsr/detail?id=269) 。JSR 269 以前咱们也有注解这样的神器,但是咱们好比想要作什么必须使用反射,反射的方法局限性较大。首先,它必须定义@Retention为RetentionPolicy.RUNTIME,只能在运行时经过反射来获取注解值,使得运行时代码效率下降。其次,若是想在编译阶段利用注解来进行一些检查,对用户的某些不合理代码给出错误报告,反射的使用方法就无能为力了。而 JSR 269 以后咱们能够在 Javac的编译期利用注解作这些事情。因此咱们发现核心的区分是在 运行期 仍是 编译期。
从上图可知,Annotation Processing 是在解析和生成之间的一个步骤。具体详细步骤以下:
上图是 Lombok 处理流程,在Javac 解析成抽象语法树以后(AST), Lombok 根据本身的注解处理器,动态的修改 AST,增长新的节点(所谓代码),最终经过分析和生成字节码。
自从Java 6起,javac就支持“JSR 269 Pluggable Annotation Processing API”规范,只要程序实现了该API,就能在javac运行的时候获得调用。
- 经常使用的项目管理工具Maven所使用的java编译工具来源于配置的第三方工具,若是咱们配置这个第三方工具为Oracle javac的话,那么Maven也就直接支持lombok了;
- Intellij Idea配置的编译工具为Oracle javac的话,也就直接支持lombok了。
IDE工具问题解决:
如今有一个A类,其中有一些字段,没有建立它们的setter和getter方法,使用了lombok的@Data注解,另外有一个B类,它调用了A类实例的相应字段的setter和getter方法
编译A类和B类所在的项目,并不会报错,由于最终生成的A类字节码文件中存在相应字段的setter和getter方法
可是,IDE发现B类源代码中所使用的A类实例的setter和getter方法在A类源代码中找不到定义,IDE会认为这是错误
要解决以上这个不是真正错误的错误,能够下载安装Intellij Idea中的"Lombok plugin"。
本文参考连接:segmentfaul【阿宝哥】https://segmentfault.com/a/1190000020864572
本文参考连接:微信公众号【江南一点雨】https://mp.weixin.qq.com/s/-4W5-fOK0sGSaNBktXA-YQ
本文参考连接:掘金【猿码道】https://juejin.im/post/6844903557016076302