六、其他重要的Lombok注解
@Cleanup注解 与 @SneakyThrows注解
@Cleanup注解
@Cleanup注解可以生成对资源进行关闭的代码,无须手动通过try-catch-finally代码块判断并关闭所有的资源
在test包下新建CleanupAnnotationTest,测试@Cleanup注解
代码语言:javascript复制public class CleanupAnnotationTest {
public void copyFile(String in, String out) throws Exception{
@Cleanup FileInputStream fileInputStream = new FileInputStream(in);
@Cleanup FileOutputStream fileOutputStream = new FileOutputStream(out);
int r;
while ((r = fileInputStream.read()) != -1){
fileOutputStream.write(r);
}
}
public static void main(String[] args) {
}
}
@Cleanup注解使用在需要关闭资源的变量名前。执行main方法,查看target目录下生成的class文件
这里自动生成了try-catch-finally代码块对资源进行了关闭操作,可以防止资源未关闭导致的性能问题
@SneakyThrows
@SneakyThrows方法只能作用在方法上,@SneakyThrows注解代替程序中的手动抛出异常代码既对受检异常进行捕捉并抛出
新建SneakyThrowsAnnotationTest测试类,将CleanupAnnotationTest的copyFile代码拷贝至SneakyThrowsAnnotationTest类下
代码语言:javascript复制public class SneakyThrowsAnnotationTest {
@Test
@SneakyThrows
public void copyFile(String in, String out){
@Cleanup FileInputStream fileInputStream = new FileInputStream(in);
@Cleanup FileOutputStream fileOutputStream = new FileOutputStream(out);
int r;
while ((r = fileInputStream.read()) != -1){
fileOutputStream.write(r);
}
}
}
添加了@SneakyThrows注解后,无须在方法上抛出异常,程序也不会报错
根据编译后的class文件可以确定,SneakyThrowsAnnotationTest类中有两层try-catch,最外层就是方法上添加了@SneakyThrows注解生成的异常处理代码。内层try-catch-finally则是资源关闭的代码
@Accessors注解
@Accessor注解是用于配置getter/setter方法生成的结果;Accessor是存取器、访问器的意思。@Accessor注解包含了三个属性分别是fluent、chain和prefix
chain 属性
在entity包下新建Porsche实体类,chain 属性可以设置为true或者false
代码语言:javascript复制@Data
@Accessors(chain = true)
public class Porsche {
private Integer id;
private String name;
private Double price;
private Integer stock;
}
运行maven的complie命令,查看target目录下的编译后的class文件
@Accessor(chain=true)注解会在@Data注解生成的setter方法基础上做修改,将setter方法的返回值由void修改为实体类类型,因此可以执行链式操作
在test包下新建PorscheTest
代码语言:javascript复制public class PorscheTest {
@Test
public void testAccessorAnnotationChain(){
Porsche prosche = new Porsche();
prosche.setId(1).setName("Taycan").setPrice(880000.00).setStock(110);
System.out.println(prosche);
}
}
设置对象属性时,仅仅一行代码就可以搞定;执行测试方法
fluent 属性
在entity包下新建Tesla实体类,fluent属性可以设置true或者false
代码语言:javascript复制@Data
@Accessors(fluent = true)
public class Tesla {
private Integer id;
private String vehicleName;
private String vehicleType;
private String vehiclePrice;
private String factory;
}
运行maven的compile编译命令,查看target目录下编译后的Tesla实体类的class文件
@Accessor注解fluent=true会在chain=true的基础上将getter/setter的方法名改为属性名
在test包下新增TeslaTest测试类
代码语言:javascript复制public class TeslaTest {
@Test
public void testAccessorAnnotationFluent(){
Tesla tesla = new Tesla();
tesla.id(1).vehicleName("Model S").vehicleType("轿跑").vehiclePrice("880000").factory("上海超级工厂");
System.out.println(tesla);
}
}
相比chain=true属性的设置,fluent=true将getter/setter方法名进行了统一,调用属性名的方法时如果传参就相当于调用setter方法,如果不传参就相当于调用getter方法;
执行测试方法
prefix属性
prefix属性可以将指定的前缀表示去除,在entity包新建Jaugar实体类
代码语言:javascript复制@Data
@Accessors(prefix = "j")
public class Jaugar {
private Integer jId;
private String jName;
private Double jPrice;
}
点击maven的compile命令,查看target目录下的Jaguar class文件
@Accessors(prefix = "j")注解在@Data生成的getter/setter方法的基础上,将指定的前缀去除
七、Lombok中 @Slf4j 日志注解使用
@Slf4j可以简化日志的引入,用于代替以下这段代码
代码语言:javascript复制private static final Logger logger = LoggerFactory.getLogger(Xxx.class);
上图中slf4j和commons-loggin都是日志规范;logback jdk-logging log4j log4j2都是日志实现。想要做到日志统一就需要用到桥接包,也可以参考SLF4J官网给出的解决方案
@Slf4j注解
首先添加相关的Jar包支持
代码语言:javascript复制<!-- 日志规范 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.36</version>
</dependency>
<!-- 日志实现 -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.11</version>
<scope>test</scope>
</dependency>
在test包中新建一个LogAnnotationTest测试类,使用@Slf4j注解
代码语言:javascript复制@Slf4j
public class LogAnnotationTest {
@Test
public void testLogger(){
log.error("这是输出的日志信息");
}
}
执行testLogger方法
查看编译后的文件
自动帮我们生成了一个构造方法,并且定义了一个log属性,这个属性是slf4j的LoggerFactory通过调用getLogger方法返回的,并且通过接口来输出日志,这也是比较推荐的方法
八、对象创建 @Builder注解 与 @Singular注解
@Builder注解
@Builder注解的作用将对象的创建和使用完全分割开来,对象的创建只能用@Builder来创建,创建完成之后,对象不可变,可以使用这个对象,但是不能修改,这也符合高耦合低内聚的原则。
在test包下新建一个BuilderAnnotationTest测试类
代码语言:javascript复制@Builder
@Data
public class BuilderAnnotationTest {
private static String staticField;
private final String finalField;
private final String initFinalField = "已经初始化的字段";
private String field;
public static void main(String[] args) {
// 创建BuilderAnnotationTest对象
// 首先调用builder方法创建一个可以链式赋值的对象
BuilderAnnotationTest builderAnnotationTest = BuilderAnnotationTest.builder()
.finalField("手动赋值字段finalField")
// 其他属性不能赋值
.field("手动赋值field")
// 创建对象,此时创建的对象是不可变的
.build();
System.out.println(builderAnnotationTest);
}
}
执行main方法
根据控制台的输出说明可以成功创建对象
查看target目录下编译后的代码
@Builder注解帮我们创建了一个构造方法
定义了一个builder方法来创建对象BuilderAnnotationTestBuilder 内部类
其中getter/setter/hashcode/equals方法都是@Data注解生成的
@Builder注解生成的内部类
这个类包含两个属性和一个空参构造方法,以及几个以属性名为方法名的方法,用于给属性赋值,还包含了toString方法以及build方法,build方法就是用于创建BuilderAnnotationTest对象的方法,使用了内部的两个属性,调用BuilderAnnotationTest上面的包含两个参数的构造方法来创建对象
总结下来就是创建一个内部类,用来持久化需要赋值的属性的属性值,并且使用这些属性通过调用构造方法来创建一个不可变的对象,对象创建过程对外是不可见的,所以对象是不可修改的
给普通属性赋值,再次调用main方法,查看创建出来的对象的普通属性的值是否会变化
普通属性的初始值创建对象的时候不会带过来;默认的值如果不手动赋值,是不会带过来的
@Singular注解
@Singular注解配合@Builder注解使用,可以简化集合类型的操作 给BuilderAnnotationTest类增加一个List列表属性,测试@Singular如何简化操作
代码语言:javascript复制private List<String> listFields;
修改main方法,手动给list属性赋值
代码语言:javascript复制public static void main(String[] args) {
// 创建BuilderAnnotationTest对象
// 首先调用builder方法创建一个可以链式赋值的对象
BuilderAnnotationTest builderAnnotationTest = BuilderAnnotationTest.builder()
.finalField("手动赋值字段finalField")
// 其他属性不能赋值
.field("手动赋值field")
.listFields(new ArrayList<>())
// 创建对象,此时创建的对象是不可变的
.build();
执行main方法
列表属性上添加@Singular注解
代码语言:javascript复制@Singular
private List<String> listFields;
再次手动给列表属性赋值
有两个方法可以进行赋值
@Singular注解可以对集合属性生成单独追加单个元素的方法,并且可以连续追加。执行测试
listField方法赋值成功。也可以连续调用listField赋值多个元素到列表中
执行测试
说明连续调用赋值也是成功的
查看target目录下生成的class代码
listField方法可以接收一个单独的String类型参数,并将该参数加入到初始化号的listFields 中,相当于帮我们解决了集合为空的时候如何填入第一个元素
还生成了一个clearListFields方法,当集合不为空的时候清除集合
调用build方法的时候会判断集合是否为空,集合为空的时候会创建一个空的list赋值给集合属性,如果只有一个元素的时候,会创建一个singletonList赋值给列表,最后创建一个不可变的集合赋值给列表属性