Lombok 是一种 Java 实用工具,可用来帮助开发人员消除 Java 的冗长,尤其是对于简单的 Java 对象(POJO)。它通过注释实现这一目的。通过在开发环境中实现 Lombok,开发人员可以节省构建诸如 hashCode()
和 equals()
、getter / setter
这样的方法以及以往用来分类各种 accessor 和 mutator 的大量时间。
Lombok 安装
使 IntelliJ IDEA 支持 Lombok 方式如下:
-
Intellij 设置支持注解处理
点击 File > Settings > Build > Annotation Processors
勾选 Enable annotation processing
-
安装插件
点击 Settings > Plugins > Browse repositories
查找 Lombok Plugin 并进行安装
重启 IntelliJ IDEA
-
将 lombok 添加到 pom 文件
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.6</version> <scope>provided</scope> </dependency>
Lombok 使用
官网API
Lombok 提供注解API 来修饰指定的类:
@Getter and @Setter
@Getter and @Setter Lombok 代码: @Getter @Setter private boolean employed = true; @Setter(AccessLevel.PROTECTED) private String name; 等价于 Java 源码: private boolean employed = true; private String name; public boolean isEmployed() { return employed; } public void setEmployed(final boolean employed) { this.employed = employed; } protected void setName(final String name) { this.name = name; }
@NonNull
@NonNull Lombok 代码: @Getter @Setter @NonNull private List<Person> members; 等价于 Java 源码: @NonNull private List<Person> members; public Family(@NonNull final List<Person> members) { if (members == null) throw new java.lang.NullPointerException("members"); this.members = members; } @NonNull public List<Person> getMembers() { return members; } public void setMembers(@NonNull final List<Person> members) { if (members == null) throw new java.lang.NullPointerException("members"); this.members = members; }
@ToString
@ToString Lombok 代码: @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 + ")"; } }
@EqualsAndHashCode
@EqualsAndHashCode Lombok 代码: @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 { /*public static final*/ Male /* = new Gender() */, /*public static final*/ Female /* = new 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; } }
@Data
@Data Lombok 代码: @Data(staticConstructor="of") public class Company { private final Person founder; private String name; private List<Person> employees; } 等价于 Java 源码: public class Company { private final Person founder; private String name; private List<Person> employees; private Company(final Person founder) { this.founder = founder; } public static Company of(final Person founder) { return new Company(founder); } public Person getFounder() { return founder; } public String getName() { return name; } public void setName(final String name) { this.name = name; } public List<Person> getEmployees() { return employees; } public void setEmployees(final List<Person> employees) { this.employees = employees; } @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; final Company other = (Company)o; if (this.founder == null ? other.founder != null : !this.founder.equals(other.founder)) return false; if (this.name == null ? other.name != null : !this.name.equals(other.name)) return false; if (this.employees == null ? other.employees != null : !this.employees.equals(other.employees)) return false; return true; } @java.lang.Override public int hashCode() { final int PRIME = 31; int result = 1; result = result * PRIME + (this.founder == null ? 0 : this.founder.hashCode()); result = result * PRIME + (this.name == null ? 0 : this.name.hashCode()); result = result * PRIME + (this.employees == null ? 0 : this.employees.hashCode()); return result; } @java.lang.Override public java.lang.String toString() { return "Company(founder=" + founder + ", name=" + name + ", employees=" + employees + ")"; } } 所有属性的get和set方法 toString 方法 hashCode方法 equals方法
@Cleanup
@Cleanup Lombok 代码: public void testCleanUp() { try { @Cleanup ByteArrayOutputStream baos = new ByteArrayOutputStream(); baos.write(new byte[] {'Y','e','s'}); System.out.println(baos.toString()); } catch (IOException e) { e.printStackTrace(); } } 等价于 Java 源码: public void testCleanUp() { try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); try { baos.write(new byte[]{'Y', 'e', 's'}); System.out.println(baos.toString()); } finally { baos.close(); } } catch (IOException e) { e.printStackTrace(); } }
@Synchronized
@Synchronized Lombok 代码: private DateFormat format = new SimpleDateFormat("MM-dd-YYYY"); @Synchronized public String synchronizedFormat(Date date) { return format.format(date); } 等价于 Java 源码: private final java.lang.Object $lock = new java.lang.Object[0]; private DateFormat format = new SimpleDateFormat("MM-dd-YYYY"); public String synchronizedFormat(Date date) { synchronized ($lock) { return format.format(date); } }
@SneakyThrows
@SneakyThrows Lombok 代码: @SneakyThrows public void testSneakyThrows() { throw new IllegalAccessException(); } Exception in thread "main" java.lang.IllegalAccessException at com.topcheer.springboot01.Test.main(Test.java:15) 等价于 Java 源码: public void testSneakyThrows() { try { throw new IllegalAccessException(); } catch (java.lang.Throwable $ex) { throw lombok.Lombok.sneakyThrow($ex); } } java.lang.IllegalAccessException at com.topcheer.springboot01.Test.main(Test.java:13) 示例 使用 Lombok 定义一个 Java Bean import lombok.Data; import lombok.ToString; @Data @ToString(exclude = "age") public class Person { private String name; private Integer age; private String sex; } 测试 Person person = new Person(); person.setName("张三"); person.setAge(20); person.setSex("男"); System.out.println(person.toString()); // output: Person(name=张三, sex=男)
其他说明
@AllArgsConstructor 这个注解是所有的参数构造器 @NoArgsConstructor 无参构造 @RequiredArgsConstructor 为每个需要特殊处理的字段生成一个带有1个参数的构造函数,且生成的构造为私有,需要通过设置 staticName 来获取访问; @RequiredArgsConstructor 功能 生成一个包含必填参数的构造函数 注意 要与@NonNull 搭配使用,该注解修饰的属性就是必填参数 源码 @RequiredArgsConstructor public class LombokDemo { @NonNull private Integer id; private String name; } 编译后 package xyz.mrwood.study.lombok; import java.beans.ConstructorProperties; import lombok.NonNull; public class LombokDemo { @NonNull private Integer id; private String name; @ConstructorProperties({"id"}) public LombokDemo(@NonNull Integer id) { if(id == null) { throw new NullPointerException("id"); } else { this.id = id; } } } @NoAragsConstructor 功能 添加一个无参构造函数 注意 这个注解在没有其它有参构造函数的情况下使用意义不大,因为在这种情况下java默认会添加一个无参构造函数 源码 @NoArgsConstructor public class LombokDemo { private Integer id; private String name; } 编译后 package xyz.mrwood.study.lombok; public class LombokDemo { private Integer id; private String name; public LombokDemo() { } } @AllArgsConstructor 功能 添加一个所有参数的构造函数 源码 @AllArgsConstructor public class LombokDemo { private Integer id; private String name; } 编译后 package xyz.mrwood.study.lombok; import java.beans.ConstructorProperties; public class LombokDemo { private Integer id; private String name; @ConstructorProperties({"id", "name"}) public LombokDemo(Integer id, String name) { this.id = id; this.name = name; } }
@Value
@Value 功能 不可变类的@Date, 他会默认给属性加上final 源码 @Value public class LombokDemo { private Integer id; private String name; } 编译后 package xyz.mrwood.study.lombok; import java.beans.ConstructorProperties; public final class LombokDemo { private final Integer id; private final String name; @ConstructorProperties({"id", "name"}) public LombokDemo(Integer id, String name) { this.id = id; this.name = name; } public Integer getId() { return this.id; } public String getName() { return this.name; } public boolean equals(Object o) { if(o == this) { return true; } else if(!(o instanceof LombokDemo)) { return false; } else { LombokDemo other = (LombokDemo)o; Integer this$id = this.getId(); Integer other$id = other.getId(); if(this$id == null) { if(other$id != null) { return false; } } else if(!this$id.equals(other$id)) { return false; } String this$name = this.getName(); String other$name = other.getName(); if(this$name == null) { if(other$name != null) { return false; } } else if(!this$name.equals(other$name)) { return false; } return true; } } public int hashCode() { boolean PRIME = true; byte result = 1; Integer $id = this.getId(); int result1 = result * 59 + ($id == null?43:$id.hashCode()); String $name = this.getName(); result1 = result1 * 59 + ($name == null?43:$name.hashCode()); return result1; } public String toString() { return "LombokDemo(id=" + this.getId() + ", name=" + this.getName() + ")"; } }
@Builder
注解提供了一种比较推崇的构建值对象的方式 Dog dog = Dog.builder().age(12).name("大黄").build(); System.out.println(dog); //Dog(name=大黄, age=12) 但是的确很有创意,这些注解已经在jar中提供,只不过它是归在”lombok.experimental.” 包中;而基本功能在”lombok.” 包中。 @Builder.Default private Boolean flag = false; //Dog(name=大黄, age=12, flag=false) 初始化的时候会把值带进去,适合有默认值的
@Accessors 定制流畅的访问器。
@Accessors(chain=true) 链式访问,该注解设置chain=true,生成setter方法返回this,代替了默认的返回void。 package com.pollyduan; import lombok.Data; import lombok.experimental.Accessors; @Data @Accessors(chain=true) public class User { private Integer id; private String name; private Integer age; public static void main(String[] args) { User user=new User().setAge(31).setName("pollyduan"); System.out.println(user); } @Accessors(fluent = true) 与chain=true类似,区别在于getter和setter不带set和get前缀。
@val @var
使用Lombok ,java也能够像javascript一样使用弱类型定义变量了 val注解变量申明是final类型 var注解变量是非final类型 import java.util.ArrayList; import java.util.HashMap; import 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()); } } } 翻译后 import java.util.ArrayList; import java.util.HashMap; import java.util.Map; 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()); } } }
@UtilityClass
功能 把普通类转为工具类 源码 @UtilityClass public class LombokDemo { private Integer id = 1; private String name = "kiwi"; public void util(){ System.out.println("xxx"); } } 编译后 package xyz.mrwood.study.lombok; public final class LombokDemo { private static Integer id = Integer.valueOf(1); private static String name = "kiwi"; public static void util() { System.out.println("xxx"); } private LombokDemo() { throw new UnsupportedOperationException("This is a utility class and cannot be instantiated"); } }
资料