## 前言
老铁/老妹们好 (。・∀・)ノ゙!
今天阿昌分享的是常用的Lombok
注解,官方地址 ,github地址
做Java开发的,哪个不知道这小辣椒呢。Lombok是一个可以通过简单的注解形式
来帮助我们简化消除一些必须有但显得很臃肿
的Java代码
的工具,提高开发人员的开发效率,通过使用对应的注解,可以在编译源码的时候生成对应的方法。
IDEA安装
1 2 3 4 5 <dependency > <groupId > org.projectlombok</groupId > <artifactId > lombok</artifactId > </dependency >
常用注解 官方注解的介绍
1、@Data
@Data
is a convenient shortcut annotation that bundles the features of @ToString
, @EqualsAndHashCode
, @Getter
/ @Setter
and @RequiredArgsConstructor
is a convenient shortcut annotation that bundles the features of @ToString
, @EqualsAndHashCode
, @Getter
/ @Setter
and @RequiredArgsConstructor
together
@Data注解在类上,会为类的所有属性自动生成setter/getter、equals、canEqual、hashCode、toString方法。
注意点
带有注解的参数(如callSuper
、includeFieldNames
和exclude
)不能用 设置@Data
所有生成的 getter 和 setter 都是public
. 要覆盖访问级别,请使用显式@Setter
和/或@Getter
注释对字段或类进行注释
所有标记为的字段transient
都不会被考虑用于hashCode
和equals
。
所有静态
字段都将被完全跳过(不考虑任何生成的方法,并且不会为它们制作 setter/getter)。
@Data(staticConstructor="of") class Foo<T> { private T x;}
您可以Foo
通过编写:Foo.of(5);
而不是必须编写:来创建新实例new Foo<Integer>(5);
。
使用Lombok
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @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 value; } }
不使用Lombok
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 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 getName () { return this .name; } void setAge (int age) { this .age = age; } public int getAge () { return this .age; } public void setScore (double score) { this .score = score; } public double getScore () { return this .score; } public String[] getTags() { return this .tags; } public void setTags (String[] tags) { this .tags = tags; } @Override public String toString () { return "DataExample(" + this .getName() + ", " + this .getAge() + ", " + this .getScore() + ", " + Arrays.deepToString(this .getTags()) + ")" ; } protected boolean canEqual (Object other) { return other instanceof DataExample; } @Override public boolean equals (Object o) { if (o == this ) return true ; if (!(o instanceof DataExample)) return false ; DataExample other = (DataExample) o; if (!other.canEqual((Object)this )) return false ; if (this .getName() == null ? other.getName() != null : !this .getName().equals(other.getName())) return false ; if (this .getAge() != other.getAge()) return false ; if (Double.compare(this .getScore(), other.getScore()) != 0 ) return false ; if (!Arrays.deepEquals(this .getTags(), other.getTags())) return false ; return true ; } @Override public int hashCode () { final int PRIME = 59 ; int result = 1 ; final long temp1 = Double.doubleToLongBits(this .getScore()); result = (result*PRIME) + (this .getName() == null ? 43 : this .getName().hashCode()); result = (result*PRIME) + this .getAge(); result = (result*PRIME) + (int )(temp1 ^ (temp1 >>> 32 )); result = (result*PRIME) + Arrays.deepHashCode(this .getTags()); return result; } public static class Exercise <T> { private final String name; private final T value; private Exercise (String name, T value) { this .name = name; this .value = value; } public static <T> Exercise<T> of (String name, T value) { return new Exercise <T>(name, value); } public String getName () { return this .name; } public T getValue () { return this .value; } @Override public String toString () { return "Exercise(name=" + this .getName() + ", value=" + this .getValue() + ")" ; } protected boolean canEqual (Object other) { return other instanceof Exercise; } @Override public boolean equals (Object o) { if (o == this ) return true ; if (!(o instanceof Exercise)) return false ; Exercise<?> other = (Exercise<?>) o; if (!other.canEqual((Object)this )) return false ; if (this .getName() == null ? other.getValue() != null : !this .getName().equals(other.getName())) return false ; if (this .getValue() == null ? other.getValue() != null : !this .getValue().equals(other.getValue())) return false ; return true ; } @Override public int hashCode () { final int PRIME = 59 ; int result = 1 ; result = (result*PRIME) + (this .getName() == null ? 43 : this .getName().hashCode()); result = (result*PRIME) + (this .getValue() == null ? 43 : this .getValue().hashCode()); return result; } } }
2、@Getter/@Setter
You can annotate any field with @Getter
and/or @Setter
, to let lombok generate the default getter/setter automatically.
使用@Getter
和/或注释任何字段@Setter
,让 lombok 自动生成默认的 getter/setter
。
注意点
默认 getter 仅返回该字段,并getFoo()
在该字段被调用foo
(或isFoo
该字段的类型为boolean
)时命名。
setFoo()
如果该字段被调用foo
、返回void
并采用与该字段相同类型的 1 个参数,则会命名默认设置器。它只是将字段设置为此值。
可以使用注解属性中AccessLevel.NONE
来设置访问级别,为任何字段手动禁用 getter/setter 生成。
使用Lombok
1 2 3 4 5 6 7 8 9 10 11 12 public class GetterSetterExample { @Getter @Setter private int age = 10 ; @Setter(AccessLevel.PROTECTED) private String name; @Override public String toString () { return String.format("%s (age: %d)" , name, age); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public class GetterSetterExample { private int age = 10 ; private String name; @Override public String toString () { return String.format("%s (age: %d)" , name, age); } public int getAge () { return age; } public void setAge (int age) { this .age = age; } protected void setName (String name) { this .name = name; } }
3、@NonNull
You can use @NonNull
on a record component, or a parameter of a method or constructor. This will cause to lombok generate a null-check statement for you.
@NonNull
在记录组件、方法或构造函数的参数上使用。lombok 会为此生成一个空检查语句
。
可选择指定,如果出错后抛出的异常是什么
1 2 lombok.nonNull.exceptionType = [ NullPointerException| IllegalArgumentException| JDK| Guava| Assertion]
1 2 3 4 5 6 7 8 public class NonNullExample extends Something { private String name; public NonNullExample (@NonNull Person person) { super ("Hello" ); this .name = person.getName(); } }
1 2 3 4 5 6 7 8 9 10 public class NonNullExample extends Something { private String name; public NonNullExample (@NonNull Person person) { super ("Hello" ); if (person == null ) { throw new NullPointerException ("person is marked @NonNull but is null" ); } this .name = person.getName(); } }
4、@Cleanup
You can use @Cleanup
to ensure a given resource is automatically cleaned up before the code execution path exits your current scope
@Cleanup
可在代码执行路径退出当前范围之前自动清理给定资源
1 2 3 4 5 6 7 8 9 10 11 12 public class CleanupExample { 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); } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public class CleanupExample { public static void main (String[] args) throws IOException { InputStream in = new FileInputStream (args[0 ]); try { OutputStream out = new FileOutputStream (args[1 ]); try { byte [] b = new byte [10000 ]; while (true ) { int r = in.read(b); if (r == -1 ) break ; out.write(b, 0 , r); } } finally { if (out != null ) { out.close(); } } } finally { if (in != null ) { in.close(); } } } }
5、@EqualsAndHashCode
Any class definition may be annotated with @EqualsAndHashCode
to let lombok generate implementations of the equals(Object other)
and hashCode()
methods
使用注释@EqualsAndHashCode
来让 lombok 生成equals(Object other)
和hashCode()
方法的实现
注意点
为类自动生成equals
andhashCode
方法是一个不好的想法,因为其父类也可能定义了字段,这些字段也需要 equals/hashCode 代码,所以该类就不会生成方法。
通过设置callSuper
到真正的 ,可以包括equals
和hashCode
你的父类中生成的方法的方法。
使用Lombok
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 @EqualsAndHashCode public class EqualsAndHashCodeExample { private transient int transientVar = 10 ; private String name; private double score; @EqualsAndHashCode .Exclude private Shape shape = new Square (5 , 10 ); private String[] tags; @EqualsAndHashCode .Exclude private int id; public String getName () { return this .name; } @EqualsAndHashCode(callSuper=true) public static class Square extends Shape { private final int width, height; public Square (int width, int height) { this .width = width; this .height = height; } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 public class EqualsAndHashCodeExample { private transient int transientVar = 10 ; private String name; private double score; private Shape shape = new Square (5 , 10 ); private String[] tags; private int id; public String getName () { return this .name; } @Override public boolean equals (Object o) { if (o == this ) return true ; if (!(o instanceof EqualsAndHashCodeExample)) return false ; EqualsAndHashCodeExample other = (EqualsAndHashCodeExample) o; if (!other.canEqual((Object)this )) return false ; if (this .getName() == null ? other.getName() != null : !this .getName().equals(other.getName())) return false ; if (Double.compare(this .score, other.score) != 0 ) return false ; if (!Arrays.deepEquals(this .tags, other.tags)) return false ; return true ; } @Override public int hashCode () { final int PRIME = 59 ; int result = 1 ; final long temp1 = Double.doubleToLongBits(this .score); result = (result*PRIME) + (this .name == null ? 43 : this .name.hashCode()); result = (result*PRIME) + (int )(temp1 ^ (temp1 >>> 32 )); result = (result*PRIME) + Arrays.deepHashCode(this .tags); return result; } protected boolean canEqual (Object other) { return other instanceof EqualsAndHashCodeExample; } public static class Square extends Shape { private final int width, height; public Square (int width, int height) { this .width = width; this .height = height; } @Override public boolean equals (Object o) { if (o == this ) return true ; if (!(o instanceof Square)) return false ; Square other = (Square) o; if (!other.canEqual((Object)this )) return false ; if (!super .equals(o)) return false ; if (this .width != other.width) return false ; if (this .height != other.height) return false ; return true ; } @Override public int hashCode () { final int PRIME = 59 ; int result = 1 ; result = (result*PRIME) + super .hashCode(); result = (result*PRIME) + this .width; result = (result*PRIME) + this .height; return result; } protected boolean canEqual (Object other) { return other instanceof Square; } } }
6、@ToString
Any class definition may be annotated with @ToString
to let lombok generate an implementation of the toString()
method.
任何类定义都可以使用注释@ToString
来让 lombok 生成toString()
方法的实现。
注意点
默认情况下,将打印所有非静态
字段,并会按顺序打印您的类名以及每个字段,并以逗号分隔
。
通过将includeFieldNames
参数设置为true, 您可以为toString()
方法的输出增加一些清晰度(但也有一定的长度)。
可使用@ToString.Exclude
,来跳过你想跳过的某些字段。
设置callSuper
为true ,可以将父类的toString
的输出包含到输出中。
可以通过@ToString.Include(rank = -1)
,来更改成员的打印顺序
。
rank的默认值为0
更高等级的成员首先打印
相同等级的成员按照它们在源文件中出现的相同顺序打印。
使用Lombok
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 @ToString public class ToStringExample { private static final int STATIC_VAR = 10 ; private String name; private Shape shape = new Square (5 , 10 ); private String[] tags; @ToString .Exclude private int id; public String getName () { return this .name; } @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; } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 public class ToStringExample { private static final int STATIC_VAR = 10 ; private String name; private Shape shape = new Square (5 , 10 ); private String[] tags; private int id; public String getName () { return this .getName(); } public static class Square extends Shape { private final int width, height; public Square (int width, int height) { this .width = width; this .height = height; } @Override public String toString () { return "Square(super=" + super .toString() + ", width=" + this .width + ", height=" + this .height + ")" ; } } @Override public String toString () { return "ToStringExample(" + this .getName() + ", " + this .shape + ", " + Arrays.deepToString(this .tags) + ")" ; } }
7、@NoArgsConstructor/@RequiredArgsConstructor/@AllArgsConstructor
This set of 3 annotations generate a constructor that will accept 1 parameter for certain fields, and simply assigns this parameter to the field.
生成一个构造函数,该构造函数将接受某些字段的 1 个参数,并简单地将此参数分配给该字段。
注意点
@NoArgsConstructor
将生成一个无参
构造器。
如果该类,存在只有一个没有初始化的final属性,那就会编译出错,可通过@NoArgsConstructor(force = true)
,为final属性初始化0
/ false
/ null
@RequiredArgsConstructor
生成一个带有 1 个参数
的构造器。
所有未初始化的final
字段都会获得一个参数0
/ false
/ null
@AllArgsConstructor
为类中的每个字段生成一个带有 1 个参数
的构造器。
使用Lombok
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @RequiredArgsConstructor(staticName = "of") @AllArgsConstructor(access = AccessLevel.PROTECTED) public class ConstructorExample <T> { private int x, y; @NonNull private T description; @NoArgsConstructor public static class NoArgsExample { @NonNull private String field; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 public class ConstructorExample <T> { private int x, y; @NonNull private T description; private ConstructorExample (T description) { if (description == null ) throw new NullPointerException ("description" ); this .description = description; } public static <T> ConstructorExample<T> of (T description) { return new ConstructorExample <T>(description); } @java .beans.ConstructorProperties({"x" , "y" , "description" }) protected ConstructorExample (int x, int y, T description) { if (description == null ) throw new NullPointerException ("description" ); this .x = x; this .y = y; this .description = description; } public static class NoArgsExample { @NonNull private String field; public NoArgsExample () { } } }
8、@Builder
The @Builder
annotation produces complex builder APIs for your classes.
为类生成一个静态复杂的构建器 API
1 2 3 4 5 6 7 8 9 @Builder public class BuilderExample { @Builder .Default private long created = System.currentTimeMillis(); private String name; private int age; @Singular private Set<String> occupations; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 public class BuilderExample { private long created; private String name; private int age; private Set<String> occupations; BuilderExample(String name, int age, Set<String> occupations) { this .name = name; this .age = age; this .occupations = occupations; } private static long $default $created() { return System.currentTimeMillis(); } public static BuilderExampleBuilder builder () { return new BuilderExampleBuilder (); } public static class BuilderExampleBuilder { private long created; private boolean created$set; private String name; private int age; private java.util.ArrayList<String> occupations; BuilderExampleBuilder() { } public BuilderExampleBuilder created (long created) { this .created = created; this .created$set = true ; return this ; } public BuilderExampleBuilder name (String name) { this .name = name; return this ; } public BuilderExampleBuilder age (int age) { this .age = age; return this ; } public BuilderExampleBuilder occupation (String occupation) { if (this .occupations == null ) { this .occupations = new java .util.ArrayList<String>(); } this .occupations.add(occupation); return this ; } public BuilderExampleBuilder occupations (Collection<? extends String> occupations) { if (this .occupations == null ) { this .occupations = new java .util.ArrayList<String>(); } this .occupations.addAll(occupations); return this ; } public BuilderExampleBuilder clearOccupations () { if (this .occupations != null ) { this .occupations.clear(); } return this ; } public BuilderExample build () { Set<String> occupations = ...; return new BuilderExample (created$set ? created : BuilderExample.$default $created(), name, age, occupations); } @java .lang.Override public String toString () { return "BuilderExample.BuilderExampleBuilder(created = " + this .created + ", name = " + this .name + ", age = " + this .age + ", occupations = " + this .occupations + ")" ; } } }
1 Person.builder().age(1 ).name("achang" ).build();
9、@Log
You put the variant of @Log
on your class (whichever one applies to the logging system you use); you then have a static final log
field, initialized as is the commonly prescribed way for the logging framework you use, which you can then use to write log statements.
从静态工厂中获取一个打印日志的对象
注意点
有多种日志种类
可供选择:
@CommonsLog
1 private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(LogExample.class);
@Flogger
1 private static final com.google.common.flogger.FluentLogger log = com.google.common.flogger.FluentLogger.forEnclosingClass();
@JBossLog
1 private static final org.jboss.logging.Logger log = org.jboss.logging.Logger.getLogger(LogExample.class);
@Log
1 private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(LogExample.class.getName());
@Log4j
1 private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(LogExample.class);
@Log4j2
1 private static final org.apache.logging.log4j.Logger log = org.apache.logging.log4j.LogManager.getLogger(LogExample.class);
@Slf4j
1 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LogExample.class);
@XSlf4j
1 private static final org.slf4j.ext.XLogger log = org.slf4j.ext.XLoggerFactory.getXLogger(LogExample.class);
@CustomLog
1 private static final com.foo.your.Logger log = com.foo.your.LoggerFactory.createYourLogger(LogExample.class);
使用Lombok
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 @Log public class LogExample { public static void main (String... args) { log.severe("Something's wrong here" ); } } @Slf4j public class LogExampleOther { public static void main (String... args) { log.error("Something else is wrong here" ); } } @CommonsLog(topic="CounterLog") public class LogExampleCategory { public static void main (String... args) { log.error("Calling the 'CounterLog' with a message" ); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public class LogExample { private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(LogExample.class.getName()); public static void main (String... args) { log.severe("Something's wrong here" ); } } public class LogExampleOther { private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LogExampleOther.class); public static void main (String... args) { log.error("Something else is wrong here" ); } } public class LogExampleCategory { private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog("CounterLog" ); public static void main (String... args) { log.error("Calling the 'CounterLog' with a message" ); } }
10、@SneakyThrows
@SneakyThrows
can be used to sneakily throw checked exceptions without actually declaring this in your method’s throws
clause. This somewhat contentious ability should be used carefully
@SneakyThrows
可用于自动的抛出已检查的异常,而无需在方法的throws
子句中实际声明。
1 2 3 4 5 6 7 8 9 10 11 public class SneakyThrowsExample implements Runnable { @SneakyThrows(UnsupportedEncodingException.class) public String utf8ToString (byte [] bytes) { return new String (bytes, "UTF-8" ); } @SneakyThrows public void run () { throw new Throwable (); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class SneakyThrowsExample implements Runnable { public String utf8ToString (byte [] bytes) { try { return new String (bytes, "UTF-8" ); } catch (UnsupportedEncodingException e) { throw Lombok.sneakyThrow(e); } } public void run () { try { throw new Throwable (); } catch (Throwable t) { throw Lombok.sneakyThrow(t); } } }
11、@Accessors
The @Accessors
annotation is used to configure how lombok generates and looks for getters and setters.
链式调用 ,在@Accessors
龙目岛是如何产生并寻找getter和setter方法的注释用于配置。
注意点
chain
– 一个布尔值。如果为true ,则生成的 setter 返回this
而不是void
。 默认值:false ,除非fluent=true
,然后默认值:true 。
使用案例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class TestLombok { public static void main (String[] args) { Person achang = Person.builder().age(1 ).name("achang" ).build(); achang.setAge(18 ).setName("阿昌" ); } @Data @Builder @Accessors(chain = true) public static class Person { private Integer age; private String name; } }
Lombok的优缺点 又到了Lombok最具有争议性的话题了,他的优缺点。
优点
让代码更加的简洁干净
开发时,只需要在实体类上标记注解即可,提升了开发的效率
缺点
不支持多种参数构造器的重载
大大降低了源代码的可读性和完整性,降低了阅读源代码的舒适度(因为会省略很多东西)
它会十分严重影响打包的效率
结尾 Lombok最大的优点就是让代码更加的简洁干净
,但是我们从上面的各个注解看过来,有一些的注解会改变我们的编码习惯,让我们后期去查看源码的时候,就不能按照Java官方的语法的查看,而是Lombok的编码。
但要记住,它只是一个工具,这个工具再怎么强大,也是要被使用者使用。Lombok有它的许许多多的优点,也有它逃避不了的缺点,我们需要做的是熟练的知道其优缺点,在我们实战中灵活运用才是王道。
以上就是这次分享的所有内容,感谢你能看到这里 (๑′ㅂ`๑)