h5在哪个网站上做,域名服务器在哪个国家,做网站学习,wordpress设置登陆口点击上方“Java知音”#xff0c;选择“置顶公众号”技术文章第一时间送达#xff01;作者#xff1a;semlinkerwww.segmentfault.com/a/1190000020864572一、Lombok 简介Lombok 是一款 Java 开发插件#xff0c;使得 Java 开发者可以通过其定义的一些注解来消除业务工程中… 点击上方“Java知音”选择“置顶公众号”技术文章第一时间送达作者semlinkerwww.segmentfault.com/a/1190000020864572一、Lombok 简介Lombok 是一款 Java 开发插件使得 Java 开发者可以通过其定义的一些注解来消除业务工程中冗长和繁琐的代码尤其对于简单的 Java 模型对象(POJO)。在开发环境中使用 Lombok 插件后Java 开发人员可以节省出重复构建诸如 hashCode 和 equals 这样的方法以及各种业务对象模型的 accessor 和 toString 等方法的大量时间。对于这些方法Lombok 能够在编译源代码期间自动帮我们生成这些方法但并不会像反射那样降低程序的性能。二、Lombok 安装2.1 构建工具Gradle在 build.gradle 文件中添加 lombok 依赖dependencies { compileOnly org.projectlombok:lombok:1.18.10 annotationProcessor org.projectlombok:lombok:1.18.10}Maven在 Maven 项目的 pom.xml 文件中添加 lombok 依赖dependency groupIdorg.projectlombokgroupId artifactIdlombokartifactId version1.18.10version scopeprovidedscopedependencyAnt假设在 lib 目录中已经存在 lombok.jar然后设置 javac 任务javac srcdirsrc destdirbuild source1.8 classpath locationlib/lombok.jar /javac2.2 IDE由于 Lombok 仅在编译阶段生成代码所以使用 Lombok 注解的源代码在 IDE 中会被高亮显示错误针对这个问题可以通过安装 IDE 对应的插件来解决。这里不详细展开具体的安装方式可以参考:https://www.baeldung.com/lombok-ide三、Lombok 详解注意以下示例所使用的 Lombok 版本是 1.18.103.1 Getter and Setter 注解你可以使用 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 {};}使用示例package com.semlinker.lombok;GetterSetterpublic class GetterAndSetterDemo { String firstName; String lastName; LocalDate dateOfBirth;}以上代码经过 Lombok 编译后会生成如下代码package com.semlinker.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 GetterGetter 注解支持一个 lazy 属性该属性默认为 false。当设置为 true 时会启用延迟初始化即当首次调用 getter 方法时才进行初始化。示例package com.semlinker.lombok;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 编译后会生成如下代码package com.semlinker.lombok;public class LazyGetterDemo { private final String notLazy this.createValue(not lazy); private final AtomicReference 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则会在同步代码块中执行初始化操作。3.2 Constructor AnnotationsNoArgsConstructor 注解使用 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;}示例package com.semlinker.lombok;NoArgsConstructor(staticName getInstance)public class NoArgsConstructorDemo { private long id; private String name; private int age;}以上代码经过 Lombok 编译后会生成如下代码package com.semlinker.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;}示例package com.semlinker.lombok;AllArgsConstructorpublic class AllArgsConstructorDemo { private long id; private String name; private int age;}以上代码经过 Lombok 编译后会生成如下代码package com.semlinker.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; }}RequiredArgsConstructorDemo 注解使用 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;}示例package com.semlinker.lombok;RequiredArgsConstructorpublic class RequiredArgsConstructorDemo { private final long id; private String name; private int age;}以上代码经过 Lombok 编译后会生成如下代码package com.semlinker.lombok;public class RequiredArgsConstructorDemo { private final long id; private String name; private int age; public RequiredArgsConstructorDemo(long id) { this.id id; }}3.3 EqualsAndHashCode 注解使用 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 ; }}示例package com.semlinker.lombok;EqualsAndHashCodepublic class EqualsAndHashCodeDemo { String firstName; String lastName; LocalDate dateOfBirth;}以上代码经过 Lombok 编译后会生成如下代码package com.semlinker.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; }}3.4 ToString 注解使用 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 ; }}示例package com.semlinker.lombok;ToString(exclude {dateOfBirth})public class ToStringDemo { String firstName; String lastName; LocalDate dateOfBirth;}以上代码经过 Lombok 编译后会生成如下代码package com.semlinker.lombok;public class ToStringDemo { String firstName; String lastName; LocalDate dateOfBirth; public ToStringDemo() { } public String toString() { return ToStringDemo(firstName this.firstName , lastName this.lastName ); }}3.5 Data 注解Data 注解与同时使用以下的注解的效果是一样的ToStringGetterSetterRequiredArgsConstructorEqualsAndHashCodeData 注解的定义如下Target(ElementType.TYPE)Retention(RetentionPolicy.SOURCE)public interface Data { String staticConstructor() default ;}示例package com.semlinker.lombok;Datapublic class DataDemo { private Long id; private String summary; private String description;}以上代码经过 Lombok 编译后会生成如下代码package com.semlinker.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() ); }}3.6 Log 注解若你将 Log 的变体放在类上(适用于你所使用的日志记录系统的任何一种)之后你将拥有一个静态的 final log 字段然后你就可以使用该字段来输出日志。Logprivate static final java.util.logging.Logger log java.util.logging.Logger.getLogger(LogExample.class.getName());Log4jprivate static final org.apache.log4j.Logger log org.apache.log4j.Logger.getLogger(LogExample.class);Log4j2private static final org.apache.logging.log4j.Logger log org.apache.logging.log4j.LogManager.getLogger(LogExample.class);Slf4jprivate static final org.slf4j.Logger log org.slf4j.LoggerFactory.getLogger(LogExample.class);XSlf4jprivate static final org.slf4j.ext.XLogger log org.slf4j.ext.XLoggerFactory.getXLogger(LogExample.class);CommonsLogprivate static final org.apache.commons.logging.Log log org.apache.commons.logging.LogFactory.getLog(LogExample.class);3.7 Synchronized 注解Synchronized 是同步方法修饰符的更安全的变体。与 synchronized 一样该注解只能应用在静态和实例方法上。它的操作类似于 synchronized 关键字但是它锁定在不同的对象上。synchronized 关键字应用在实例方法时锁定的是 this 对象而应用在静态方法上锁定的是类对象。对于 Synchronized 注解声明的方法来说它锁定的是 $LOCK 或 $lock。Synchronized 注解的定义如下Target(ElementType.METHOD)Retention(RetentionPolicy.SOURCE)public interface Synchronized { // 指定锁定的字段名称 String value() default ;}示例package com.semlinker.lombok;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 编译后会生成如下代码package com.semlinker.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); } }}3.8 Builder 注解使用 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; }}示例package com.semlinker.lombok;Builderpublic class BuilderDemo { private final String firstname; private final String lastname; private final String email;}以上代码经过 Lombok 编译后会生成如下代码package com.semlinker.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 ); } }}3.9 SneakyThrows 注解SneakyThrows 注解用于自动抛出已检查的异常而无需在方法中使用 throw 语句显式抛出。SneakyThrows 注解的定义如下Target({ElementType.METHOD, ElementType.CONSTRUCTOR})Retention(RetentionPolicy.SOURCE)public interface SneakyThrows { // 设置你希望向上抛的异常类 Class extends Throwable[] value() default java.lang.Throwable.class;}示例package com.semlinker.lombok;public class SneakyThrowsDemo { SneakyThrows Override protected Object clone() { return super.clone(); }}以上代码经过 Lombok 编译后会生成如下代码package com.semlinker.lombok;public class SneakyThrowsDemo { public SneakyThrowsDemo() { } protected Object clone() { try { return super.clone(); } catch (Throwable var2) { throw var2; } }}3.10 NonNull 注解你可以在方法或构造函数的参数上使用 NonNull 注解它将会为你自动生成非空校验语句。NonNull 注解的定义如下Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.LOCAL_VARIABLE, ElementType.TYPE_USE})Retention(RetentionPolicy.CLASS)Documentedpublic interface NonNull {}示例package com.semlinker.lombok;public class NonNullDemo { Getter Setter NonNull private String name;}以上代码经过 Lombok 编译后会生成如下代码package com.semlinker.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; } }}3.11 Clean 注解Clean 注解用于自动管理资源用在局部变量之前在当前变量范围内即将执行完毕退出之前会自动清理资源自动生成 try-finally 这样的代码来关闭流。Target(ElementType.LOCAL_VARIABLE)Retention(RetentionPolicy.SOURCE)public interface Cleanup { // 设置用于执行资源清理/回收的方法名称对应方法不能包含任何参数默认名称为close。 String value() default close;}示例package com.semlinker.lombok;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 编译后会生成如下代码package com.semlinker.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(); } } }}3.11 With 注解在类的字段上应用 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); }}3.12 其它特性valval 用在局部变量前面相当于将变量声明为 final此外 Lombok 在编译时还会自动进行类型推断。val 的使用示例public class ValExample { public String example() { val example new ArrayList(); example.add(Hello, World!); val foo example.get(0);return foo.toLowerCase(); }public void example2() { val map new HashMap();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 ArrayListString example new ArrayListString(); example.add(Hello, World!); final String foo example.get(0); return foo.toLowerCase(); } public void example2() { final HashMapString map new HashMapString(); map.put(0, zero); map.put(5, five);for (final Map.EntryString entry : map.entrySet()) { System.out.printf(%d: %s\n, entry.getKey(), entry.getValue()); } }}至此功能强大的 Lombok 工具就介绍完了。若你对于它的实现原理感兴趣的话建议阅读:https://www.jianshu.com/p/63038c7c515a示例项目地址https://github.com/semlinker/springstack/tree/master/springboot2-lombok四、参考资源https://projectlombok.org/https://interviewbubble.com/lombok-cheatsheet/http://blog.didispace.com/java-lombok-how-to-use/ENDJava面试题专栏【01期】SpringSpringMVCSpringBootSpringCloud有什么区别和联系【02期】你能说说Spring框架中Bean的生命周期吗【03期】如何决定使用 HashMap 还是 TreeMap【04期】分库分表之后id 主键如何处理【05期】消息队列中如何保证消息的顺序性【06期】单例模式有几种写法【07期】Redis中是如何实现分布式锁的【08期】说说Object类下面有几种方法呢【09期】说说hashCode() 和 equals() 之间的关系【10期】Redis 面试常见问答我知道你 “在看”