lombok想必已经有不少人已经使用了很长时间了,而我倒是第一次接触到,有点呆。lombok主要是用于减小重复代码,经过一组简单的注释取代一些重复的Java代码。对于lombok的评价褒贬不一,有的人以为特别方便,有的人以为改变了一成不变的代码结构,增长了代码维护成本(有的人没有用过lombok),我是以为每个工具诞生确定是有他诞生的价值的,多学一个是一个啊,小老弟,用不用再说。:)html
官方文档地址java
官方API地址git
官方注解介绍地址github
我这里已经安装好了,没有安装的时候按钮应该是Installweb
<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.2</version> <scope>provided</scope> </dependency>
顾名思义,生成get和set方法的注解,@Getter和@Setter发生在编译阶段,编译以后,@Getter和@Setter相关的注解就消失了,取而代之的是相应的get和set方法。数组
public class LombokTest { @Getter @Setter private boolean flag; }
lombok遵循了boolean类型的get方法的约定,咱们来看一下编译后的代码(等效Java代码)吧。maven
public class LombokTest { private boolean flag; public LombokTest() { } public boolean isFlag() { return this.flag; } public void setFlag(boolean flag) { this.flag = flag; } }
能够看到boolean类型的get方法是isFlag()而不是getFlag()。咱们还可定义生成get和set方法的访问级别。ide
public class LombokTest { @Getter(AccessLevel.PUBLIC) @Setter(AccessLevel.PROTECTED) private String name; }
编译后的代码(等效Java代码)函数
public class LombokTest { private String name; public LombokTest() { } public String getName() { return this.name; } protected void setName(String name) { this.name = name; } }
能够看到setName的访问级别是protected。lombok提供了下面几种级别。
AccessLevel枚举类的源代码。
public enum AccessLevel { PUBLIC, // public MODULE, // 编译后至关于 default PROTECTED, // protected PACKAGE, // default PRIVATE, // private NONE; // 不生成 private AccessLevel() { } }
最后@Getter和@Setter注解是能够写在类级别的,做用于全部的成员变量,没法细粒度的控制访问级别。
@Getter(AccessLevel.MODULE) @Setter(AccessLevel.PROTECTED) public class LombokTest { private String name; private boolean flag; }
编译后的代码(等效Java代码)
public class LombokTest { private String name; private boolean flag; public LombokTest() { } String getName() { return this.name; } boolean isFlag() { return this.flag; } protected void setName(String name) { this.name = name; } protected void setFlag(boolean flag) { this.flag = flag; } }
变量空检查,若是@NonNull注解使用在构造函数的字段时,构造函数也会进行空变量检查。不可用于类级别。
public class LombokTest { @NonNull @Setter @Getter private String name; public LombokTest(@NonNull String name) { this.name = name; } }
编译后的代码(等效Java代码)
public class LombokTest { @NonNull private String name; public LombokTest(@NonNull String name) { if (name == null) { throw new NullPointerException("name is marked @NonNull but is null"); } else { this.name = name; } } public void setName(@NonNull String name) { if (name == null) { throw new NullPointerException("name is marked @NonNull but is null"); } else { this.name = name; } } @NonNull public String getName() { return this.name; } }
用于生成toString()方法。只能用于类级别。static修饰的变量是不能生成在toString()方法中的,缘由是static修饰的变量在类建立的时候就生成了,只有一个;而普通的变量属于对象,每建立一个新的对象都会有一个。能够理解为static修饰的变量属于类,而普通变量数据对象,这样可能好理解一点。
@ToString public class LombokTest { private String name; private static String phone; }
编译后的代码(等效Java代码)
public class LombokTest { private String name; private static String phone; public LombokTest() { } public String toString() { return "YmlProperties(name=" + this.name + ")"; } }
默认状况下出了static修饰的字段都将以name-value的形式生成在toString()方法中。同时toString注解中还能够设置一些属性来细粒度的控制toString()方法。
下面是ToString注解的源码和解释:
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.SOURCE) public @interface ToString { boolean includeFieldNames() default true; // 生成toString()方法时默认为 name-value的形式,设置为false时 则 value的形式。 String[] exclude() default {}; // 不包含指定字段 String[] of() default {}; // 包含指定字段 boolean callSuper() default false; // 是否调用父类的toString()方法 boolean doNotUseGetters() default false; // 生成toString()方法是否直接访问字段,设置为true时直接访问字段(如:this.name),false时经过getter()方法进行访问(如:this.getName())。固然若是没有生成getter()方法,不管是否设置都直接访问字段 boolean onlyExplicitlyIncluded() default false; // 是否仅仅包含添加了@ToString.Include的字段,默认为false。 @Target({ElementType.FIELD}) @Retention(RetentionPolicy.SOURCE) public @interface Exclude { // 使用@ToString.Exclude修饰字段,须要和@ToString注解一块儿使用,单独使用无效。 } @Target({ElementType.FIELD, ElementType.METHOD}) @Retention(RetentionPolicy.SOURCE) public @interface Include {// 使用@ToString.Include修饰字段,须要和@ToString注解一块儿使用,单独使用无效。 int rank() default 0; String name() default ""; } }
注意:
@ToString(of = {"name","phone"}) // 包含name和phone字段 @ToString(exclude = {"name","phone"}) // 不包含name和phone字段
@ToString public class LombokTest { @ToString.Include private String name; @ToString.Exclude private String phone; }
生成equals()和hashCode()方法。默认使用全部的非static和非transient字段生成这两个方法。
@EqualsAndHashCode public class LombokTest { private String name; private String phone; private boolean flag; }
编译后的代码(等效Java代码)
public class LombokTest { private String name; private String phone; private boolean flag; public LombokTest() { } public boolean equals(Object o) { if (o == this) { return true; } else if (!(o instanceof LombokTest)) { return false; } else { LombokTest other = (LombokTest)o; if (!other.canEqual(this)) { return false; } else { label39: { Object this$name = this.name; Object other$name = other.name; if (this$name == null) { if (other$name == null) { break label39; } } else if (this$name.equals(other$name)) { break label39; } return false; } Object this$phone = this.phone; Object other$phone = other.phone; if (this$phone == null) { if (other$phone != null) { return false; } } else if (!this$phone.equals(other$phone)) { return false; } if (this.flag != other.flag) { return false; } else { return true; } } } } protected boolean canEqual(Object other) { return other instanceof LombokTest; } public int hashCode() { int PRIME = true; int result = 1; Object $name = this.name; int result = result * 59 + ($name == null ? 43 : $name.hashCode()); Object $phone = this.phone; result = result * 59 + ($phone == null ? 43 : $phone.hashCode()); result = result * 59 + (this.flag ? 79 : 97); return result; } }
和ToString注解类似也能够经过设置一些属性来控制决堤生成的hashCode()和equals()方法。下面是@EqualsAndHashCode注解的源码和解释,和@ToString同样的属性就没有写注释了。
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.SOURCE) public @interface EqualsAndHashCode { String[] exclude() default {}; String[] of() default {}; boolean callSuper() default false;// 是否使用父类的equals和toString方法,注意:父类为Object时没法设置为true。 boolean doNotUseGetters() default false; EqualsAndHashCode.AnyAnnotation[] onParam() default {}; boolean onlyExplicitlyIncluded() default false; /** @deprecated */ @Deprecated @Retention(RetentionPolicy.SOURCE) @Target({}) public @interface AnyAnnotation { // 过期的方法(deprecated) } @Target({ElementType.FIELD}) @Retention(RetentionPolicy.SOURCE) public @interface Exclude { } @Target({ElementType.FIELD, ElementType.METHOD}) @Retention(RetentionPolicy.SOURCE) public @interface Include { String replaces() default ""; } }
这是lombok中使用的最多的注解,至关于@ToString
,@EqualsAndHashCode
, @RequiredArgsConstructor
,@Getter
和@Setter
五个注解的功能。虽然使用起来方法,可是失去了细粒度的控制。若是须要细粒度控制,则须要进行注解的覆盖。
@Data public class LombokTest { private String name; private String phone; private boolean flag; }
编译后的代码(等效Java代码)
public class LombokTest { private String name; private String phone; private boolean flag; public LombokTest() { } public String getName() { return this.name; } public String getPhone() { return this.phone; } public boolean isFlag() { return this.flag; } public void setName(String name) { this.name = name; } public void setPhone(String phone) { this.phone = phone; } public void setFlag(boolean flag) { this.flag = flag; } public boolean equals(Object o) { if (o == this) { return true; } else if (!(o instanceof LombokTest)) { return false; } else { LombokTest other = (LombokTest)o; if (!other.canEqual(this)) { return false; } else { label39: { Object this$name = this.getName(); Object other$name = other.getName(); if (this$name == null) { if (other$name == null) { break label39; } } else if (this$name.equals(other$name)) { break label39; } return false; } Object this$phone = this.getPhone(); Object other$phone = other.getPhone(); if (this$phone == null) { if (other$phone != null) { return false; } } else if (!this$phone.equals(other$phone)) { return false; } if (this.isFlag() != other.isFlag()) { return false; } else { return true; } } } } protected boolean canEqual(Object other) { return other instanceof LombokTest; } public int hashCode() { int PRIME = true; int result = 1; Object $name = this.getName(); int result = result * 59 + ($name == null ? 43 : $name.hashCode()); Object $phone = this.getPhone(); result = result * 59 + ($phone == null ? 43 : $phone.hashCode()); result = result * 59 + (this.isFlag() ? 79 : 97); return result; } public String toString() { return "LombokTest(name=" + this.getName() + ", phone=" + this.getPhone() + ", flag=" + this.isFlag() + ")"; } }
下面看一下@Data注解的源码。
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.SOURCE) public @interface Data { String staticConstructor() default ""; }
能够看到提供了一个,staticConstructor(),这个方法的做用是私有化构造器,并生成一个静态的获取实例的方法,这样就可经过类名来获取实例(如:LombokTest.getLombokTest())
@Data(staticConstructor = "getLombokTest")
private LombokTest() { } public static LombokTest getLombokTest() { return new LombokTest(); } // ...省略其余代码
自动释放资源,主要用于IO流的操做,不须要手动编写释放资源的try/finally
代码块。
public class LombokTest { public static void main(String[] args) throws Exception { @Cleanup InputStream is = new FileInputStream(args[0]); @Cleanup OutputStream os = new FileOutputStream(args[0]); } }
编译后的代码(等效Java代码)
public class LombokTest { public static void main(String[] args) throws Exception { FileInputStream is = new FileInputStream(args[0]); try { OutputStream os = new FileOutputStream(args[0]); if (Collections.singletonList(os).get(0) != null) { os.close(); } } finally { if (Collections.singletonList(is).get(0) != null) { is.close(); } } } }
仍是挺方便的。再来看看@Cleanup注解的源代码
@Target({ElementType.LOCAL_VARIABLE}) @Retention(RetentionPolicy.SOURCE) public @interface Cleanup { String value() default "close"; }
能够看到默认调用的是close方法,也就是说咱们能够设置finally方法体具体调用的流处理方法。如:
public static void main(String[] args) throws Exception { @Cleanup(value = "available") InputStream is = new FileInputStream(args[0]); @Cleanup OutputStream os = new FileOutputStream(args[0]); }
编译后的代码(等效Java代码)
具体能够指定哪些字段,须要流对象支持哪些方法了。如InputStream:
同步代码块,只能使用在类方法(static)或者对象方法(普通方法)上,synchronized关键字锁住的是this,@Synchronized注解默认使用的锁为$lock,静态的锁为$LOCK,也能够本身指定锁对象,如示例中的:world
public class LombokTest { @Synchronized public void hello() { } @Synchronized public static void helloWorld() { } private final Object world = new Object(); @Synchronized("world") public void world() { } }
编译后的代码(等效Java代码)
public class LombokTest { private final Object $lock = new Object[0]; private static final Object $LOCK = new Object[0]; private final Object world = new Object(); public LombokTest() { } public void hello() { Object var1 = this.$lock; synchronized(this.$lock) { ; } } public static void helloWorld() { Object var0 = $LOCK; synchronized($LOCK) { ; } } public void world() { Object var1 = this.world; synchronized(this.world) { ; } } }
我的以为没有啥意义,惟一的做用可能就是不用手动捕获异常或者向上抛出,而是经过lombok帮你捕获。。。能够指定捕获的异常类型,默认捕获的是Throwable。
public class LombokTest { @SneakyThrows() public void testSneakyThrows() { throw new IllegalAccessException(); } @SneakyThrows(IllegalAccessException.class) public void testSneakyThrows2() { throw new IllegalAccessException(); } }
编译后的代码(等效Java代码)
public class LombokTest { public LombokTest() { } public void testSneakyThrows() { try { throw new IllegalAccessException(); } catch (Throwable var2) { throw var2; } } public void testSneakyThrows2() { try { throw new IllegalAccessException(); } catch (IllegalAccessException var2) { throw var2; } } }
感受有点呆。。。官方建议在没有深思熟虑以前不要使用这个注解。。。下面是官网上的一句话:
@SneakyThrows
annotation. If you pass no exceptions, you may throw any exception sneakily.@NoArgsConstructor 生成一个无参构造器。
@NoArgsConstructor注解源代码,另外两个注解的源码和这个很相似,就不贴出来了。
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.SOURCE) public @interface NoArgsConstructor { String staticName() default ""; // 若是指定了相应字段,则私有化构造并生成一个静态的获取实例方法。 NoArgsConstructor.AnyAnnotation[] onConstructor() default {}; AccessLevel access() default AccessLevel.PUBLIC; boolean force() default false; /** @deprecated */ @Deprecated @Retention(RetentionPolicy.SOURCE) @Target({}) public @interface AnyAnnotation { // 过期的(deprecated) } }
@ RequiredArgsConstructor 生成包含必须处理的字段的构造器,如:final修饰(必须初始化)、@NonNull注解修饰的。
@RequiredArgsConstructor public class LombokTest { private String name; private String phone; private transient boolean flag; private final String finalFiled; private static int num; }
编译后的代码(等效Java代码)
public class LombokTest { private String name; private String phone; private transient boolean flag; private final String finalFiled; private static int num; public LombokTest(String finalFiled) { this.finalFiled = finalFiled; } }
@ AllArgsConstructor 生成一个全参构造器,除static修饰的字段。@NonNull能够组合使用。
@AllArgsConstructor public class LombokTest { private String name; @NonNull private String phone; private transient boolean flag; private final String finalFiled; private static int num; }
编译后的代码(等效Java代码)
public class LombokTest { private String name; @NonNull private String phone; private transient boolean flag; private final String finalFiled; private static int num; public LombokTest(String name, @NonNull String phone, boolean flag, String finalFiled) { if (phone == null) { throw new NullPointerException("phone is marked @NonNull but is null"); } else { this.name = name; this.phone = phone; this.flag = flag; this.finalFiled = finalFiled; } } }
学到这里经常使用的Lombok注解基本上都有了,若是想要根据深刻的学习,建议去官网看。官网地址文章开始已经列出来了,加油!!!