Project Lombok是一个java库,它可以自动插入到编辑器和构建工具中,为Java增添趣味。 永远不要再编写另一个getter或equals方法,只要有一个注释,你的类就有一个功能齐全的构建器,自动化你的日志变量,等等。
val
用在局部变量前面,相当于将变量声明为 final
val map = new HashMap<String, String>();
// 相当于
final Map<String, String> map = new HashMap<>();
但是这个功能不能再 IDEA 中正确运行
@NonNull
给 属性、方法参数 增加这个注解会自动在方法内对该参数进行是否为空的校验。
形参前加上@NonNull,当传入参数为null时,会抛出 NPE(NullPointerException)
不加@NonNull,会打印结果null,不会抛异常
修饰属性:
public class UserLombok {
private Long id;
private String name;
@NonNull
private String school;
}
修饰方法参数:
public void testNonNull(@NonNull String name) {
System.out.println(name);
}
// 相当于
public void testNonNull(String name) {
if (name != null) {
System.out.println(name);
} else {
throw new NullPointerException("null");
}
}
@Cleanup
自动管理资源,用在局部变量之前,在当前变量范围内即将执行完毕退出之前会自动清理资源,自动生成 try-finally
这样的代码来关闭流
public static void main(String[] args) {
try {
@Cleanup InputStream inputStream = new FileInputStream(args[0]);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
// 相当于
InputStream inputStream = null;
try {
inputStream = new FileInputStream(args[0]);
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
@Getter/@Setter
标注在类上
标注在类上,表示针对该类中所有的非静态字段进行 get、set 方法自动生成。
标注在字段上
标注在字段上,用于自动生成 get、set 方法,boolean 类型字段 get 方法为 isXXX() 方法。
生成的 get、set 方法默认情况下都是 public 的,但也可以手动指定以下四种范围:
- AccessLevel.PUBLIC
- AccessLevel.MODULE
- AccessLevel.PROTECTED
- AccessLevel.PACKAGE
- AccessLevel.PRIVATE
@Data
public class User {
private String name;
@Setter(AccessLevel.PRIVATE) // 生成的Setter方法是private的
private String address;
@Setter @Getter(AccessLevel.PRIVATE) // 生成的Setter和Getter方法是private的
private String phone;
}
如果指定某个字段的 AccessLevel = AccessLevel.NONE
,则可以使该生成动作失效,此时可以手动实现get、set方法,AccessLevel.NONE
可以应用于在某些方法中有一些自定义逻辑的情况下。
@Getter
@Setter
public class User {
private String name;
private Integer age;
@Getter(value = AccessLevel.NONE)
private boolean child;
public boolean isChild() {
if(age < 12) {
return true;
}
return false;
}
}
@ToString
用在类上可以自动覆写 toString 方法,当然还可以加其他参数
例如 @ToString(exclude=”id”)
排除 id 属性,@ToString(exclude={"id", "name"})
排除多个属性
或者 @ToString(callSuper=true, includeFieldNames=true)
调用父类的 toString 方法,包含所有属性
@ToString(exclude = "id", callSuper = true, includeFieldNames = true)
publicclass LombokDemo {
private int id;
private String name;
private int age;
public static void main(String[] args) {
// 输出 LombokDemo(super=LombokDemo@48524010, name=null, age=0)
System.out.println(new LombokDemo());
}
}
@EqualsAndHashCode
用在类上自动生成 equals(Object other)
和 hashcode()
方法,包括所有非静态变量和非 transient 的变量
@EqualsAndHashCode(exclude = {"id", "name"}, callSuper = false)
public class User {
private int id;
private String name;
}
为什么要重写hashcode和equals方法
为什么只有一个整体的 @EqualsAndHashCode
注解,而不是分开的两个 @Equals
和 @HashCode
?
- 在 Java 中有规定,当两个对象 equals 时,他们的 hashcode 一定要相同,反之,当 hashcode 相同时,对象不一定 equals。所以 equals 和 hashcode 要一起实现,免得发生违反 Java 规定的情形发生
@Data
lombok 项目的产生就是为了省去我们手动创建getter和setter等基本方法的麻烦,它能够在我们编译源码的时候自动帮我们生成getter和setter等方法。即它最终能够达到的效果是:在源码中没有getter和setter方法,但是在编译生成的字节码文件中有getter和setter方法
注意:@EqualsAndHashCode注解与@ToString注解默认情况下是忽略父类的成员变量的。
在类继承的情况时应注意@Data注解不会涉父类的成员的坑,需要加callSuper = true的参数。
@Data 是整合包,只要加了 @Data 这个注解,等于同时加了以下注解
- @Getter/@Setter
- @ToString
- @EqualsAndHashCode
- @RequiredArgsConstructor
@NoArgsConstructor
@AllArgsConstructor
@RequiredArgsConstructor
@NoArgsConstructor
用在类上,自动生成无参构造器
@AllArgsConstructor
用在类上,自动生成使用所有参数的构造器
@RequiredArgsConstructor
用在类上,生成一个包含 “特定参数” 的构造器,特定参数指的是所有被 final 修饰的变量
把所有 被@NonNull 或者 final 修饰的属性作为参数的构造函数
@RequiredArgsConstructor
public class UserLombok {
private Long id;
private String name;
private String phoneNo;
private final String address;
@NonNull
private String school;
}
则会生成一个包含address和school的构造函数
指定 staticName=“of” 参数
如果指定 staticName=“of” 参数,同时还会生成一个返回类对象的静态工厂方法,比使用构造函数方便很多
@Slf4j
@RequiredArgsConstructor(staticName="of")
@AllArgsConstructor(staticName="of")
@ToString
public class UserLombok {
private Long id;
private String name;
private String phoneNo;
private final String address;
private String school;
@Test
public void test() {
UserLombok userLombok1 = UserLombok.of("cc");
UserLombok userLombok2 = UserLombok.of(2L, "hory", "155", "sh", "cc");
log.info("userLombok toString:{}", userLombok1.toString());
// userLombok toString:UserLombok(id=null, name=null, phoneNo=null, address=cc, school=null)
log.info("userLombok toString:{}", userLombok2.toString());
// userLombok toString:UserLombok(id=2, name=hory, phoneNo=155, address=sh, school=cc)
}
}
注意:
- 当我们没有指定构造器时,Java 编译器会自动生成一个没有任何参数的构造器,但是如果我们自己写了构造器之后,Java 就不会自动帮我们补上那个无参数的构造器了。
- 然而很多地方(像是 Spring Data JPA),会需要每个类都一定要有一个无参数的构造器,所以在加上
@AllArgsConstructor
时,一定要补上 @NoArgsConstrcutor
-
@AllArgsConstructor
和@NoArgsConstrcutor
是可以共用的
@Value
也是整合包,但是它会把所有的变量都设成 final 的,其他的就跟 @Data 一样,等于同时加了以下注解
- @Getter(注意没有setter)
- @ToString
- @EqualsAndHashCode
- @RequiredArgsConstructor
@Data 适合用在 POJO 或 DTO 上,而这个 @Value 注解,则是适合加在值不希望被改变的类上,像是某个类的值当创建后就不希望被更改,只希望我们读它而已,就适合加上 @Value 注解,也就是 @Value for immutable class
注意:此 lombok 的注解 @Value 和另一个 Spring 的注解 @Value 撞名,在 import 时不要 import 错了
@Builder
自动生成流式 set 值写法,从此之后再也不用写一堆 setter 了.
public class User {
private Integer id;
private String name;
public void setId(Integer id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
}
public static void main(String[] args) {
User user = new User();
user.setId(1);
user.setName("John");
}
等同于下面的写法
@Builder
public class User {
private Integer id;
private String name;
}
public static void main(String[] args) {
User user = User.builder().id(1).name("John").build();
}
注意:虽然只要加上 @Builder 注解,就能够用流式写法快速设定对象的值,但 setter 还是必须要写不能省略的,因为 Spring 或是其他框架有很多地方都会用到对象的 getter/setter 对它们取值/赋值。
所以通常是 @Data 和 @Builder 会一起用在同个类上,既方便我们流式写代码,也方便框架做事。
@SneakyThrows
https://www.cnblogs.com/acmaner/p/13967688.html
自动抛受检异常,而无需显式在方法上使用 throws 语句
publicclass ThrowsTest {
@SneakyThrows()
public void read() {
InputStream inputStream = new FileInputStream("");
}
@SneakyThrows
public void write() {
throw new UnsupportedEncodingException();
}
// 相当于
public void read() throws FileNotFoundException {
InputStream inputStream = new FileInputStream("");
}
public void write() throws UnsupportedEncodingException {
throw new UnsupportedEncodingException();
}
}
@Synchronized
用在方法上,将方法声明为同步的,并自动加锁,而锁对象是一个私有的属性 或LOCK
而 Java 中的 synchronized 关键字锁对象是 this,锁在 this 或者自己的类对象上存在副作用,就是你不能阻止非受控代码去锁 this 或者类对象,这可能会导致竞争条件或者其它线程错误
public class SynchronizedDemo {
@Synchronized
public static void hello() {
System.out.println("world");
}
// 相当于
private static final Object $LOCK = new Object[0];
public static void hello() {
synchronized ($LOCK) {
System.out.println("world");
}
}
}
@Getter(lazy=true)
可以替代经典的 Double Check Lock 样板代码
public class GetterLazyExample {
@Getter(lazy = true)
private final double[] cached = expensive();
private double[] expensive() {
double[] result = new double[1000000];
for (int i = 0; i < result.length; i++) {
result[i] = Math.asin(i);
}
return result;
}
}
相当于
import java.util.concurrent.atomic.AtomicReference;
public class GetterLazyExample {
private final AtomicReference<java.lang.Object> cached = new AtomicReference<>();
public double[] getCached() {
java.lang.Object value = this.cached.get();
if (value == null) {
synchronized (this.cached) {
value = this.cached.get();
if (value == null) {
final double[] actualValue = expensive();
value = actualValue == null ? this.cached : actualValue;
this.cached.set(value);
}
}
}
return (double[]) (value == this.cached ? null : value);
}
private double[] expensive() {
double[] result = new double[1000000];
for (int i = 0; i < result.length; i++) {
result[i] = Math.asin(i);
}
return result;
}
}
@Log
@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)
@Slf4j
自动生成该类的 log 静态常量,要打日志就可以直接打,不用再手动 new log 静态常量了
public class User {
private static final Logger log = LoggerFactory.getLogger(User.class);
public static void main(String[] args) {
log.info("hello");
}
}
等同于下面的写法
@Slf4j
public class User {
public static void main(String[] args) {
log.info("hello");
}
}
除了 @Slf4j 之外,lombok 也提供其他日志框架的变种注解可以用,像是 @Log、@Log4j…等,它们都是帮我们创建一个静态常量 log,只是使用的库不一样而已.
@Log
import java.util.logging.Logger;
@Log
private static final Logger log = Logger.getLogger(LogExample.class.getName());
@Log4j
import org.apache.log4j.Logger;
@Log4j
private static final Logger log = Logger.getLogger(LogExample.class);
log 系列注解最常用的就是 @Slf4j,SpringBoot 默认支持的就是 slf4j + logback 的日志框架,所以也不用再多做啥设定,直接就可以用在 SpringBoot project上.