Lombok有啥牛皮的?SpringBoot和IDEA官方都要支持它!
文章推薦指數: 80 %
之后在项目的pom.xml文件中添加Lombok依赖,SpringBoot 2.1.x版本后无需指定Lombok版本,SpringBoot在 spring-boot-dependencies 中已经内置。
val使用val注解可以取代任意类型作为局部变量,这样我们就不用写复杂的ArrayList和Map.Entry类型了,具体例子如下。
/**
*Createdbymacroon2020/12/16.
*/
publicclassValExample{
publicstaticvoidexample(){
//val代替ArrayList
publicclassValExample{
publicValExample(){
}
publicstaticvoidexample(){
ArrayList
/**
*Createdbymacroon2020/12/16.
*/
publicclassNonNullExample{
privateStringname;
publicNonNullExample(@NonNullStringname){
this.name=name;
}
publicstaticvoidmain(String[]args){
newNonNullExample("test");
//会抛出NullPointerException
newNonNullExample(null);
}
}编译后会在构造器中添加非空判断,具体代码如下。
publicclassNonNullExample{
privateStringname;
publicNonNullExample(@NonNullStringname){
if(name==null){
thrownewNullPointerException("nameismarkednon-nullbutisnull");
}else{
this.name=name;
}
}
publicstaticvoidmain(String[]args){
newNonNullExample("test");
newNonNullExample((String)null);
}
}@Cleanup当我们在Java中使用资源时,不可避免地需要在使用后关闭资源。
使用@Cleanup注解可以自动关闭资源。
/**
*Createdbymacroon2020/12/16.
*/
publicclassCleanupExample{
publicstaticvoidmain(String[]args)throwsIOException{
StringinStr="HelloWorld!";
//使用输入输出流自动关闭,无需编写trycatch和调用close()方法
@CleanupByteArrayInputStreamin=newByteArrayInputStream(inStr.getBytes("UTF-8"));
@CleanupByteArrayOutputStreamout=newByteArrayOutputStream();
byte[]b=newbyte[1024];
while(true){
intr=in.read(b);
if(r==-1)break;
out.write(b,0,r);
}
StringoutStr=out.toString("UTF-8");
System.out.println(outStr);
}
}编译后Lombok会生成如下代码。
publicclassCleanupExample{
publicCleanupExample(){
}
publicstaticvoidmain(String[]args)throwsIOException{
StringinStr="HelloWorld!";
ByteArrayInputStreamin=newByteArrayInputStream(inStr.getBytes("UTF-8"));
try{
ByteArrayOutputStreamout=newByteArrayOutputStream();
try{
byte[]b=newbyte[1024];
while(true){
intr=in.read(b);
if(r==-1){
StringoutStr=out.toString("UTF-8");
System.out.println(outStr);
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();
}
}
}
}@Getter/@Setter有了@Getter/@Setter注解,我们再也不用编写getter/setter方法了。
试想下之前即使我们使用IDEA自动生成getter/setter方法,如果类属性的类型和名称改了,又要重新生成getter/setter方法也是一件很麻烦的事情。
/**
*Createdbymacroon2020/12/17.
*/
publicclassGetterSetterExample{
@Getter
@Setter
privateStringname;
@Getter
@Setter(AccessLevel.PROTECTED)
privateIntegerage;
publicstaticvoidmain(String[]args){
GetterSetterExampleexample=newGetterSetterExample();
example.setName("test");
example.setAge(20);
System.out.printf("name:%sage:%d",example.getName(),example.getAge());
}
}编译后Lombok会生成如下代码。
publicclassGetterSetterExample{
privateStringname;
privateIntegerage;
publicGetterSetterExample(){
}
publicStringgetName(){
returnthis.name;
}
publicvoidsetName(finalStringname){
this.name=name;
}
publicIntegergetAge(){
returnthis.age;
}
protectedvoidsetAge(finalIntegerage){
this.age=age;
}
}@ToString把所有类属性都编写到toString方法中方便打印日志,是一件多么枯燥无味的事情。
使用@ToString注解可以自动生成toString方法,默认会包含所有类属性,使用@ToString.Exclude注解可以排除属性的生成。
/**
*Createdbymacroon2020/12/17.
*/
@ToString
publicclassToStringExample{
@ToString.Exclude
privateLongid;
privateStringname;
privateIntegerage;
publicToStringExample(Longid,Stringname,Integerage){
this.id=id;
this.name=name;
this.age=age;
}
publicstaticvoidmain(String[]args){
ToStringExampleexample=newToStringExample(1L,"test",20);
//自动实现toString方法,输出ToStringExample(name=test,age=20)
System.out.println(example);
}
}编译后Lombok会生成如下代码。
publicclassToStringExample{
privateLongid;
privateStringname;
privateIntegerage;
publicToStringExample(Longid,Stringname,Integerage){
this.id=id;
this.name=name;
this.age=age;
}
publicStringtoString(){
return"ToStringExample(name="+this.name+",age="+this.age+")";
}
}@EqualsAndHashCode使用@EqualsAndHashCode注解可以自动生成hashCode和equals方法,默认包含所有类属性,使用@EqualsAndHashCode.Exclude可以排除属性的生成。
/**
*Createdbymacroon2020/12/17.
*/
@Getter
@Setter
@EqualsAndHashCode
publicclassEqualsAndHashCodeExample{
privateLongid;
@EqualsAndHashCode.Exclude
privateStringname;
@EqualsAndHashCode.Exclude
privateIntegerage;
publicstaticvoidmain(String[]args){
EqualsAndHashCodeExampleexample1=newEqualsAndHashCodeExample();
example1.setId(1L);
example1.setName("test");
example1.setAge(20);
EqualsAndHashCodeExampleexample2=newEqualsAndHashCodeExample();
example2.setId(1L);
//equals方法只对比id,返回true
System.out.println(example1.equals(example2));
}
}编译后Lombok会生成如下代码。
publicclassEqualsAndHashCodeExample{
privateLongid;
privateStringname;
privateIntegerage;
publicEqualsAndHashCodeExample(){
}
publicbooleanequals(finalObjecto){
if(o==this){
returntrue;
}elseif(!(oinstanceofEqualsAndHashCodeExample)){
returnfalse;
}else{
EqualsAndHashCodeExampleother=(EqualsAndHashCodeExample)o;
if(!other.canEqual(this)){
returnfalse;
}else{
Objectthis$id=this.getId();
Objectother$id=other.getId();
if(this$id==null){
if(other$id!=null){
returnfalse;
}
}elseif(!this$id.equals(other$id)){
returnfalse;
}
returntrue;
}
}
}
protectedbooleancanEqual(finalObjectother){
returnotherinstanceofEqualsAndHashCodeExample;
}
publicinthashCode(){
intPRIME=true;
intresult=1;
Object$id=this.getId();
intresult=result*59+($id==null?43:$id.hashCode());
returnresult;
}
}@XxConstructor使用@XxConstructor注解可以自动生成构造方法,有@NoArgsConstructor、@RequiredArgsConstructor和@AllArgsConstructor三个注解可以使用。
@NoArgsConstructor:生成无参构造函数。
@RequiredArgsConstructor:生成包含必须参数的构造函数,使用@NonNull注解的类属性为必须参数。
@AllArgsConstructor:生成包含所有参数的构造函数。
/**
*Createdbymacroon2020/12/17.
*/
@NoArgsConstructor
@RequiredArgsConstructor(staticName="of")
@AllArgsConstructor
publicclassConstructorExample{
@NonNull
privateLongid;
privateStringname;
privateIntegerage;
publicstaticvoidmain(String[]args){
//无参构造器
ConstructorExampleexample1=newConstructorExample();
//全部参数构造器
ConstructorExampleexample2=newConstructorExample(1L,"test",20);
//@NonNull注解的必须参数构造器
ConstructorExampleexample3=ConstructorExample.of(1L);
}
}编译后Lombok会生成如下代码。
publicclassConstructorExample{
@NonNull
privateLongid;
privateStringname;
privateIntegerage;
publicConstructorExample(){
}
privateConstructorExample(@NonNullfinalLongid){
if(id==null){
thrownewNullPointerException("idismarkednon-nullbutisnull");
}else{
this.id=id;
}
}
publicstaticConstructorExampleof(@NonNullfinalLongid){
returnnewConstructorExample(id);
}
publicConstructorExample(@NonNullfinalLongid,finalStringname,finalIntegerage){
if(id==null){
thrownewNullPointerException("idismarkednon-nullbutisnull");
}else{
this.id=id;
this.name=name;
this.age=age;
}
}
}@Data@Data是一个方便使用的组合注解,是@ToString、@EqualsAndHashCode、@Getter、@Setter和@RequiredArgsConstructor的组合体。
/**
*Createdbymacroon2020/12/17.
*/
@Data
publicclassDataExample{
@NonNull
privateLongid;
@EqualsAndHashCode.Exclude
privateStringname;
@EqualsAndHashCode.Exclude
privateIntegerage;
publicstaticvoidmain(String[]args){
//@RequiredArgsConstructor已生效
DataExampleexample1=newDataExample(1L);
//@Getter@Setter已生效
example1.setName("test");
example1.setAge(20);
//@ToString已生效
System.out.println(example1);
DataExampleexample2=newDataExample(1L);
//@EqualsAndHashCode已生效
System.out.println(example1.equals(example2));
}
}编译后Lombok会生成如下代码。
publicclassDataExample{
@NonNull
privateLongid;
privateStringname;
privateIntegerage;
publicDataExample(@NonNullfinalLongid){
if(id==null){
thrownewNullPointerException("idismarkednon-nullbutisnull");
}else{
this.id=id;
}
}
@NonNull
publicLonggetId(){
returnthis.id;
}
publicStringgetName(){
returnthis.name;
}
publicIntegergetAge(){
returnthis.age;
}
publicvoidsetId(@NonNullfinalLongid){
if(id==null){
thrownewNullPointerException("idismarkednon-nullbutisnull");
}else{
this.id=id;
}
}
publicvoidsetName(finalStringname){
this.name=name;
}
publicvoidsetAge(finalIntegerage){
this.age=age;
}
publicbooleanequals(finalObjecto){
if(o==this){
returntrue;
}elseif(!(oinstanceofDataExample)){
returnfalse;
}else{
DataExampleother=(DataExample)o;
if(!other.canEqual(this)){
returnfalse;
}else{
Objectthis$id=this.getId();
Objectother$id=other.getId();
if(this$id==null){
if(other$id!=null){
returnfalse;
}
}elseif(!this$id.equals(other$id)){
returnfalse;
}
returntrue;
}
}
}
protectedbooleancanEqual(finalObjectother){
returnotherinstanceofDataExample;
}
publicinthashCode(){
intPRIME=true;
intresult=1;
Object$id=this.getId();
intresult=result*59+($id==null?43:$id.hashCode());
returnresult;
}
publicStringtoString(){
return"DataExample(id="+this.getId()+",name="+this.getName()+",age="+this.getAge()+")";
}
}@Value使用@Value注解可以把类声明为不可变的,声明后此类相当于final类,无法被继承,其属性也会变成final属性。
/**
*Createdbymacroon2020/12/17.
*/
@Value
publicclassValueExample{
privateLongid;
privateStringname;
privateIntegerage;
publicstaticvoidmain(String[]args){
//只能使用全参构造器
ValueExampleexample=newValueExample(1L,"test",20);
//example.setName("andy")//没有生成setter方法,会报错
//example.name="andy"//字段被设置为final类型,会报错
}
}编译后Lombok会生成如下代码。
publicfinalclassValueExample{
privatefinalLongid;
privatefinalStringname;
privatefinalIntegerage;
publicstaticvoidmain(String[]args){
newValueExample(1L,"test",20);
}
publicValueExample(finalLongid,finalStringname,finalIntegerage){
this.id=id;
this.name=name;
this.age=age;
}
publicLonggetId(){
returnthis.id;
}
publicStringgetName(){
returnthis.name;
}
publicIntegergetAge(){
returnthis.age;
}
}@Builder使用@Builder注解可以通过建造者模式来创建对象,建造者模式加链式调用,创建对象太方便了!/**
*Createdbymacroon2020/12/17.
*/
@Builder
@ToString
publicclassBuilderExample{
privateLongid;
privateStringname;
privateIntegerage;
publicstaticvoidmain(String[]args){
BuilderExampleexample=BuilderExample.builder()
.id(1L)
.name("test")
.age(20)
.build();
System.out.println(example);
}
}编译后Lombok会生成如下代码。
publicclassBuilderExample{
privateLongid;
privateStringname;
privateIntegerage;
BuilderExample(finalLongid,finalStringname,finalIntegerage){
this.id=id;
this.name=name;
this.age=age;
}
publicstaticBuilderExample.BuilderExampleBuilderbuilder(){
returnnewBuilderExample.BuilderExampleBuilder();
}
publicStringtoString(){
return"BuilderExample(id="+this.id+",name="+this.name+",age="+this.age+")";
}
publicstaticclassBuilderExampleBuilder{
privateLongid;
privateStringname;
privateIntegerage;
BuilderExampleBuilder(){
}
publicBuilderExample.BuilderExampleBuilderid(finalLongid){
this.id=id;
returnthis;
}
publicBuilderExample.BuilderExampleBuildername(finalStringname){
this.name=name;
returnthis;
}
publicBuilderExample.BuilderExampleBuilderage(finalIntegerage){
this.age=age;
returnthis;
}
publicBuilderExamplebuild(){
returnnewBuilderExample(this.id,this.name,this.age);
}
publicStringtoString(){
return"BuilderExample.BuilderExampleBuilder(id="+this.id+",name="+this.name+",age="+this.age+")";
}
}
}@SneakyThrows还在手动捕获并抛出异常?使用@SneakyThrows注解自动实现试试!/**
*Createdbymacroon2020/12/17.
*/
publicclassSneakyThrowsExample{
//自动抛出异常,无需处理
@SneakyThrows(UnsupportedEncodingException.class)
publicstaticbyte[]str2byte(Stringstr){
returnstr.getBytes("UTF-8");
}
publicstaticvoidmain(String[]args){
Stringstr="HelloWorld!";
System.out.println(str2byte(str).length);
}
}编译后Lombok会生成如下代码。
publicclassSneakyThrowsExample{
publicSneakyThrowsExample(){
}
publicstaticbyte[]str2byte(Stringstr){
try{
returnstr.getBytes("UTF-8");
}catch(UnsupportedEncodingExceptionvar2){
throwvar2;
}
}
}@Synchronized当我们在多个线程中访问同一资源时,往往会出现线程安全问题,以前我们往往使用synchronized关键字修饰方法来实现同步访问。
使用@Synchronized注解同样可以实现同步访问。
packagecom.macro.mall.tiny.example;
importlombok.*;
/**
*Createdbymacroon2020/12/17.
*/
@Data
publicclassSynchronizedExample{
@NonNull
privateIntegercount;
@Synchronized
@SneakyThrows
publicvoidreduceCount(Integerid){
if(count>0){
Thread.sleep(500);
count--;
System.out.println(String.format("thread-%dcount:%d",id,count));
}
}
publicstaticvoidmain(String[]args){
//添加@Synchronized三个线程可以同步调用reduceCount方法
SynchronizedExampleexample=newSynchronizedExample(20);
newReduceThread(1,example).start();
newReduceThread(2,example).start();
newReduceThread(3,example).start();
}
@RequiredArgsConstructor
staticclassReduceThreadextendsThread{
@NonNull
privateIntegerid;
@NonNull
privateSynchronizedExampleexample;
@Override
publicvoidrun(){
while(example.getCount()>0){
example.reduceCount(id);
}
}
}
}编译后Lombok会生成如下代码。
publicclassSynchronizedExample{
privatefinalObject$lock=newObject[0];
@NonNull
privateIntegercount;
publicvoidreduceCount(Integerid){
try{
synchronized(this.$lock){
if(this.count>0){
Thread.sleep(500L);
Integervar3=this.count;
Integervar4=this.count=this.count-1;
System.out.println(String.format("thread-%dcount:%d",id,this.count));
}
}
}catch(Throwablevar7){
throwvar7;
}
}
}@With使用@With注解可以实现对原对象进行克隆,并改变其一个属性,使用时需要指定全参构造方法。
@With
@AllArgsConstructor
publicclassWithExample{
privateLongid;
privateStringname;
privateIntegerage;
publicstaticvoidmain(String[]args){
WithExampleexample1=newWithExample(1L,"test",20);
WithExampleexample2=example1.withAge(22);
//将原对象进行clone并设置age,返回false
System.out.println(example1.equals(example2));
}
}编译后Lombok会生成如下代码。
publicclassWithExample{
privateLongid;
privateStringname;
privateIntegerage;
publicWithExamplewithId(finalLongid){
returnthis.id==id?this:newWithExample(id,this.name,this.age);
}
publicWithExamplewithName(finalStringname){
returnthis.name==name?this:newWithExample(this.id,name,this.age);
}
publicWithExamplewithAge(finalIntegerage){
returnthis.age==age?this:newWithExample(this.id,this.name,age);
}
publicWithExample(finalLongid,finalStringname,finalIntegerage){
this.id=id;
this.name=name;
this.age=age;
}
}@Getter(lazy=true)当我们获取某一个属性比较消耗资源时,可以给@Getter添加lazy=true属性实现懒加载,会生成DoubleCheckLock样板代码对属性进行懒加载。
/**
*Createdbymacroon2020/12/17.
*/
publicclassGetterLazyExample{
@Getter(lazy=true)
privatefinaldouble[]cached=expensive();
privatedouble[]expensive(){
double[]result=newdouble[1000000];
for(inti=0;i
延伸文章資訊
- 1Why you should not use Lombok - Bruna Pereira
- 2Java - 五分鐘學會Lombok 用法 - 古古's Blog
介紹如何使用Lombok 幫助我們提升開發效率. ... 框架,所以也不用再多做啥設定,直接就可以用在SpringBoot project上,log 系列注解最常用的就是@Slf4j.
- 3SpringBoot - 第十二章| Lombok簡單介紹使用
Project Lombok是一個java庫,可以自動插入編輯器並構建工具,為你的java ... package com.jj.learning.springboot.chapter12.mo...
- 4Lombok is awesome. Be careful with that. | Level Up Coding
- 5六角鼠年鐵人賽Week 11 - Spring Boot - Lombok 省時省力好幫手
六角鼠年鐵人賽Week 11 - Spring Boot - Lombok 省時省力好幫手. 大家好,我是“為了拿到金角獎盃而努力著” 的文毅青年- Kai. 賦得古原草送别白居易.