Lombok是什么
Lombok是一个插件,能以简单的注解形式来简化java代码,提高开发人员的开发效率。例如开发中经常需要写的javabean,都需要花时间去添加相应的getter/setter,也许还要去写构造器、equals等方法,而且需要维护,当属性多时会出现大量的getter/setter方法,这些显得很冗长也没有太多技术含量,一旦修改属性,就容易出现忘记修改对应方法的失误。
Lombok能通过注解的方式,在编译时自动为属性生成构造器、getter/setter、equals、hashcode、toString方法。出现的神奇就是在源码中没有getter和setter方法,但是在编译生成的字节码文件中有getter和setter方法。这样就省去了手动重建这些代码的麻烦,使代码看起来更简洁些。
怎么安装Lombok
对于IDEA来说,Lombok安装就比较简单,步骤如下:
在Maven中加入lombok的依赖
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
<version>1.18.2-RELEASE</version>
</dependency>
Lombok有哪些注解
@NoArgsConstructor/@RequiredArgsConstructor /@AllArgsConstructor
这三个注解都是用在类上的,第一个和第三个都很好理解,就是为该类产生无参的构造方法和包含所有参数的构造方法,第二个注解则使用类中所有带有@NonNull注解的或者带有final修饰的成员变量生成对应的构造方法,当然,和前面几个注解一样,成员变量都是非静态的。另外,如果类中含有final修饰的成员变量,是无法使用@NoArgsConstructor注解的。
三个注解都可以指定生成的构造方法的访问权限,还可指定生成一个静态方法。
@Builder
提供了一种比较推崇的构建值对象的方式
非常推荐的一种构建值对象的方式。缺点就是父类的属性不能产于builder
@Builder
public class Demo {
private final int finalVal = 10;
private String name;
private int age;
}
编译后
public class Demo {
private final int finalVal = 10;
private String name;
private int age;
Demo(String name, int age) {
this.name = name;
this.age = age;
}
public static Demo.DemoBuilder builder() {
return new Demo.DemoBuilder();
}
public static class DemoBuilder {
private String name;
private int age;
DemoBuilder() {
}
public Demo.DemoBuilder name(String name) {
this.name = name;
return this;
}
public Demo.DemoBuilder age(int age) {
this.age = age;
return this;
}
public Demo build() {
return new Demo(this.name, this.age);
}
public String toString() {
String var10000 = this.name;
return this.age;
}
}
}
构建Demo类
public static void main(String[] args) {
Demo demo = Demo.builder().name("aa").age(10).build();
System.out.println(demo);
}
@Cleanup
能够自动释放资源
这个注解用在变量前面,可以保证此变量代表的资源会被自动关闭,默认是调用资源的close()方法。如果该资源有其它关闭方法,可使用@Cleanup(“methodName”)来指定要调用的方法,就用输入输出流来举个例子吧:
public static void main(String[] args) throws Exception {
@Cleanup InputStream in = new FileInputStream(args[0]);
@Cleanup OutputStream out = new FileOutputStream(args[1]);
byte[] b = new byte[1024];
while (true) {
int r = in.read(b);
if (r == -1) break;
out.write(b, 0, r);
}
}
编译后:
public static void main(String[] args) throws Exception {
FileInputStream in = new FileInputStream(args[0]);
try {
FileOutputStream out = new FileOutputStream(args[1]);
try {
byte[] b = new byte[1024];
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();
}
}
}
@Data
强悍的组合功能包
相当于注解集合。效果等同于**@Getter + @Setter + @ToString + @EqualsAndHashCode + @RequiredArgsConstructor** 由于生成的代码篇幅太长,这里就不给demo了,反正效果同上5个注解的效果,强悍
需要注意的是,这里不包括@NoArgsConstructor和@AllArgsConstructor
@Value
和@Data类似,区别在于它会把所有成员变量默认定义为private final修饰,并且不会生成set方法。
@ToString/@EqualsAndHashCode
生成toString,equals和hashcode方法,同时后者还会生成一个canEqual方法,用于判断某个对象是否是当前类的实例。,生成方法时只会使用类中的非静态成员变量,这些都比较好理解。毕竟静态的东西并不属于对象本身
有些关键的属性,可以控制toString的输出,我们可以了解一下:
@ToString(
includeFieldNames = true, //是否使用字段名
exclude = {"name"}, //排除某些字段
of = {"age"}, //只使用某些字段
callSuper = true //是否让父类字段也参与 默认false
)
@Getter/@Setter
这一对注解从名字上就很好理解,用在成员变量上面或者类上面,相当于为成员变量生成对应的get和set方法,同时还可以为生成的方法指定访问修饰符,当然,默认为public
这两个注解直接用在类上,可以为此类里的所有非静态成员变量生成对应的get和set方法。如果是final变量,那就只会有get方法
@NonNull
这个注解可以用在成员方法或者构造方法的参数前面,会自动产生一个关于此参数的非空检查,如果参数为空,则抛出一个空指针异常。
//成员方法参数加上@NonNull注解
public String getName(@NonNull Person p){
return p.getName();
}
编译后:
public String getName(@NonNull Person p){
if(p==null){
throw new NullPointerException("person");
}
return p.getName();
}
@SneakyThrows
这个注解用在方法上,可以将方法中的代码用try-catch语句包裹起来,捕获异常并在catch中用Lombok.sneakyThrow(e)把异常抛出,可以使用@SneakyThrows(Exception.class)的形式指定抛出哪种异常
@SneakyThrows(UnsupportedEncodingException.class)
public String utf8ToString(byte[] bytes) {
return new String(bytes, "UTF-8");
}
编译后:
@SneakyThrows(UnsupportedEncodingException.class)
public String utf8ToString(byte[] bytes) {
try{
return new String(bytes, "UTF-8");
}catch(UnsupportedEncodingException uee){
throw Lombok.sneakyThrow(uee);
}
}
@Val
很强的类型推断 var注解,在Java10之后就不能使用了
Log、CommonsLog、Slf4j、XSlf4j、Log4j、Log4j2等日志注解
这个注解用在类上,可以省去从日志工厂生成日志对象这一步,直接进行日志记录,具体注解根据日志工具的不同而不同,同时,可以在注解中使用topic来指定生成log对象时的类名。不同的日志注解总结如下(上面是注解,下面是实际作用):
注解自动注入的语句对照表:
@CommonsLog
private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(LogExample.class);
@JBossLog
private static final org.jboss.logging.Logger log = org.jboss.logging.Logger.getLogger(LogExample.class);
@Log
private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(LogExample.class.getName());
@Log4j
private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(LogExample.class);
@Log4j2
private static final org.apache.logging.log4j.Logger log = org.apache.logging.log4j.LogManager.getLogger(LogExample.class);
@Slf4j
private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LogExample.class);
@XSlf4j
private static final org.slf4j.ext.XLogger log = org.slf4j.ext.XLoggerFactory.getXLogger(LogExample.class);
比如:
@Slf4j
class Parent {
}
注入后:
class Parent {
private static final Logger log = LoggerFactory.getLogger(Parent.class);
Parent() {
}
}