Lombok入门使用教程及其优缺点详解(上)

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: Lombok入门使用教程及其优缺点详解

Lombok入门使用教程及其优缺点详解


一、Lombok是什么?

1. 官方网站地址:点击直达

2. 官网对Lombok的描述如下:

Project Lombok is a java library that automatically plugs into your editor and build tools, spicing up your java.

Never write another getter or equals method again, with one annotation your class has a fully featured builder, Automate your logging variables, and much more.


简单理解后说下意思:


Lombok项目其实就是一个java库,它可以自动插入到编辑器和构建工具中,增强java的性能。以后你只需要一些简单的注解,就可以再也不用在类中反复去写get、equals等方法。


3、优点说明:

Lombok能以简单的注解形式来简化java代码,提高开发人员的开发效率。例如开发中经常需要写的javabean,都需要花时间去添加相应的getter/setter,也许还要去写构造器、equals等方法,而且需要维护,当属性多时会出现大量的getter/setter方法,这些显得很冗长也没有太多技术含量,一旦修改属性,就容易出现忘记修改对应方法的失误。


Lombok能通过注解的方式,在编译时自动为属性生成构造函数、getter/setter、equals、hashcode、toString等方法。奇妙之处在于源码中没有getter和setter方法,但是在编译生成的字节码文件中有getter和setter方法。这样就省去了手动重建这些代码的麻烦,使代码看起来更简洁明了。


二、Lombok安装与使用

1、安装Lombok插件

Lombok插件支持Eclipse、IntelliJ IDEA、MyEclispe等IDE,在这里我们使用IntelliJ IDEA来演示安装:


1)打开File > Settings > Plugins >Marketplace,搜索Lombok,如图,点击install,弹窗Accept,然后安装好后Restart IDEA。

2)设置Enable annotation processing

打开File > Settings > Build, Execution, Deployment > Compiler > Annotation Processors,勾选Enable annotation processing,然后Apply和OK。


2、新建Java项目,引入jar包

1、常用jar包引入方法有两种,如下:

方法1:普通项目可以直接官网下载jar包,和使用普通jar包一样,导入项目即可。jar下载地址:点击去下载


方法2:Maven项目可以在pom.xml中配置依赖坐标即可,依赖坐标如下:


org.projectlombok lombok 1.18.12 provided 注意:

1、provided表示该包只在编译和测试的时候用,项目真正打成包时不会将Lombok包打进去。


2、Lombok还支持其他构建方法,比如Ant、Gradle、Kobalt,有需要的可以参考官网的Install菜单下的Build Tools,其他使用方法也可以参考Install菜单


2、使用说明可以参考官方资料,也可以看我这里的常用注解代码演示(重点关注:@NonNull,@Getter, @Setter,@AllArgsConstructor,@NoArgsConstructor, @ToString和@Data)


1、官方注解:

2、官方API文档:点击直达

1)@NonNull该注解用在属性或构造器上,Lombok会生成一个非空的声明,可用于校验参数,能帮助避免空指针。

示例代码:


//成员方法参数加上@NonNull注解,构造方法也一样,在此不做演示publicStringgetName(@NonNullPersonp){
returnp.getName();
}
实际效果相当于:publicStringgetName(Personp){
if(p==null){
thrownewNullPointerException("person");
    }
returnp.getName();
}


2)@Getter和@Setter:在JavaBean或类JavaBean中使用,使用此注解相当于为成员变量生成对应的get和set方法,方法默认修饰符为public,同时还可以使用AccessLevel为生成的方法指定访问修饰符。这两个注解还可以直接用在类上,可以为此类里的所有非静态成员变量生成对应的get和set方法。

示例代码:


publicclassStudent{
@Getter@SetterprivateStringname;
@Setter(AccessLevel.PROTECTED)
privateintage;
@Getter(AccessLevel.PUBLIC)
privateStringlanguage;
}


实际效果相当于:


publicclassStudent{
privateStringname;
privateintage;
privateStringlanguage;
publicvoidsetName(Stringname){
this.name=name;
    }
publicStringgetName(){
returnname;
    }
protectedvoidsetAge(intage){
this.age=age;
    }
publicStringgetLanguage(){
returnlanguage;
    }
}



3)@Cleanup这个注解用在变量前面,可以保证此变量代表的资源会被自动关闭,默认是调用资源的close()方法,如果该资源有其它关闭方法,可使用@Cleanup(“methodName”)来指定要调用的方法。

示例代码:


publicstaticvoidmain(String[] args) throwsIOException {
@CleanupInputStreamin=newFileInputStream(args[0]);
@CleanupOutputStreamout=newFileOutputStream(args[1]);
byte[] b=newbyte[1024];
while (true) {
intr=in.read(b);
if (r==-1) break;
out.write(b, 0, r);
     }
 }


实际效果相当于:


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[1024];

    while (true) {

      int r = in.read(b);

      if (r == -1) break;

      out.write(b, 0, r);

    }

publicstaticvoidmain(String[] args) throwsIOException {
@CleanupInputStreamin=newFileInputStream(args[0]);
@CleanupOutputStreamout=newFileOutputStream(args[1]);
byte[] b=newbyte[1024];
while (true) {
intr=in.read(b);
if (r==-1) break;
out.write(b, 0, r);
     }
 }



4)@ToString在JavaBean或类JavaBean中使用,使用此注解会自动重写对应的toStirng方法,默认情况下,会输出类名、所有属性(会按照属性定义顺序),用逗号来分割,通过callSuper参数来指定是否引用父类,includeFieldNames参数设为true,就能明确的输出toString()属性。

@ToString(exclude=”column”)

意义:排除column列所对应的元素,即在生成toString方法时不包含column参数;

@ToString(exclude={“column1″,”column2″})

意义:排除多个column列所对应的元素,其中间用英文状态下的逗号进行分割,即在生成toString方法时不包含多个column参数;

@ToString(of=”column”)

意义:只生成包含column列所对应的元素的参数的toString方法,即在生成toString方法时只包含column参数;;

@ToString(of={“column1″,”column2”})

意义:只生成包含多个column列所对应的元素的参数的toString方法,其中间用英文状态下的逗号进行分割,即在生成toString方法时只包含多个column参数;

示例代码:


@ToString(exclude="id")
publicclassToStringExample {
privatestaticfinalintSTATIC_VAR=10;
privateStringname;
privateShapeshape=newSquare(5, 10);
privateString[] tags;
privateintid;
publicStringgetName() {
returnthis.getName();
  }
@ToString(callSuper=true, includeFieldNames=true)
publicstaticclassSquareextendsShape {
privatefinalintwidth, height;
publicSquare(intwidth, intheight) {
this.width=width;
this.height=height;
    }
  }
}



实际效果相当于:


publicclassToStringExample {
privatestaticfinalintSTATIC_VAR=10;
privateStringname;
privateShapeshape=newSquare(5, 10);
privateString[] tags;
privateintid;
publicStringgetName() {
returnthis.getName();
  }
publicstaticclassSquareextendsShape {
privatefinalintwidth, height;
publicSquare(intwidth, intheight) {
this.width=width;
this.height=height;
    }
@OverridepublicStringtoString() {
return"Square(super="+super.toString() +", width="+this.width+", height="+this.height+")";
    }
  }
@OverridepublicStringtoString() {
return"ToStringExample("+this.getName() +", "+this.shape+", "+Arrays.deepToString(this.tags) +")";
  }
}



5)@EqualsAndHashCode默认情况下,会使用所有非静态(non-static)和非瞬态(non-transient)属性来生成equals和hasCode,也能通过exclude注解来排除一些属性。

示例代码:



@EqualsAndHashCode(exclude={"id", "shape"})
publicclassEqualsAndHashCodeExample {
privatetransientinttransientVar=10;
privateStringname;
privatedoublescore;
privateShapeshape=newSquare(5, 10);
privateString[] tags;
privateintid;
publicStringgetName() {
returnthis.name;
  }
@EqualsAndHashCode(callSuper=true)
publicstaticclassSquareextendsShape {
privatefinalintwidth, height;
publicSquare(intwidth, intheight) {
this.width=width;
this.height=height;
    }
  }
}



6)@NoArgsConstructor、@RequiredArgsConstructor和@AllArgsConstructor

这三个注解都是用在类上的,第一个和第三个都很好理解,就是为该类产生无参的构造方法和包含所有参数的构造方法,第二个注解则使用类中所有带有@NonNull注解的或者带有final修饰的成员变量生成对应的构造方法,当然,成员变量都是非静态的,另外,如果类中含有final修饰的成员变量,是无法使用@NoArgsConstructor注解的。


三个注解都可以指定生成的构造方法的访问权限,同时,第二个注解还可以用@RequiredArgsConstructor(staticName=”methodName”)的形式生成一个指定名称的静态方法,返回一个调用相应的构造方法产生的对象。


示例代码:


/

@RequiredArgsConstructor(staticName="myShape")
@AllArgsConstructor(access=AccessLevel.PROTECTED)
@NoArgsConstructorpublicclassShape {
privateintx;
@NonNullprivatedoubley;
@NonNullprivateStringname;
}
实际效果相当于:publicclassShape {
privateintx;
privatedoubley;
privateStringname;
publicShape(){
    }
protectedShape(intx,doubley,Stringname){
this.x=x;
this.y=y;
this.name=name;
    }
publicShape(doubley,Stringname){
this.y=y;
this.name=name;
    }
publicstaticShapemyShape(doubley,Stringname){
returnnewShape(y,name);
    }
}


7)@Data注解在类上,会为类的所有属性自动生成setter/getter、equals、canEqual、hashCode、toString方法,如为final属性,则不会为该属性生成setter方法。@Value注解和@Data类似,区别在于它会把所有成员变量默认定义为private final修饰,并且不会生成set方法。

官方实例如下:


@DatapublicclassDataExample {
privatefinalStringname;
@Setter(AccessLevel.PACKAGE) privateintage;
privatedoublescore;
privateString[] tags;
@ToString(includeFieldNames=true)
@Data(staticConstructor="of")
publicstaticclassExercise<T> {
privatefinalStringname;
privatefinalTvalue;
  }
}
实际效果相当于:publicclassDataExample {
privatefinalStringname;
privateintage;
privatedoublescore;
privateString[] tags;
publicDataExample(Stringname) {
this.name=name;
  }
publicStringgetName() {
returnthis.name;
  }
voidsetAge(intage) {
this.age=age;
  }
publicintgetAge() {
returnthis.age;
  }
publicvoidsetScore(doublescore) {
this.score=score;
  }
publicdoublegetScore() {
returnthis.score;
  }
publicString[] getTags() {
returnthis.tags;
  }
publicvoidsetTags(String[] tags) {
this.tags=tags;
  }
@OverridepublicStringtoString() {
return"DataExample("+this.getName() +", "+this.getAge() +", "+this.getScore() +", "+Arrays.deepToString(this.getTags()) +")";
  }
protectedbooleancanEqual(Objectother) {
returnotherinstanceofDataExample;
  }
@Overridepublicbooleanequals(Objecto) {
if (o==this) returntrue;
if (!(oinstanceofDataExample)) returnfalse;
DataExampleother= (DataExample) o;
if (!other.canEqual((Object)this)) returnfalse;
if (this.getName() ==null?other.getName() !=null : !this.getName().equals(other.getName())) returnfalse;
if (this.getAge() !=other.getAge()) returnfalse;
if (Double.compare(this.getScore(), other.getScore()) !=0) returnfalse;
if (!Arrays.deepEquals(this.getTags(), other.getTags())) returnfalse;
returntrue;
  }
@OverridepublicinthashCode() {
finalintPRIME=59;
intresult=1;
finallongtemp1=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());
returnresult;
  }
publicstaticclassExercise<T> {
privatefinalStringname;
privatefinalTvalue;
privateExercise(Stringname, Tvalue) {
this.name=name;
this.value=value;
    }
publicstatic<T>Exercise<T>of(Stringname, Tvalue) {
returnnewExercise<T>(name, value);
    }
publicStringgetName() {
returnthis.name;
    }
publicTgetValue() {
returnthis.value;
    }
@OverridepublicStringtoString() {
return"Exercise(name="+this.getName() +", value="+this.getValue() +")";
    }
protectedbooleancanEqual(Objectother) {
returnotherinstanceofExercise;
    }
@Overridepublicbooleanequals(Objecto) {
if (o==this) returntrue;
if (!(oinstanceofExercise)) returnfalse;
Exercise<?>other= (Exercise<?>) o;
if (!other.canEqual((Object)this)) returnfalse;
if (this.getName() ==null?other.getValue() !=null : !this.getName().equals(other.getName())) returnfalse;
if (this.getValue() ==null?other.getValue() !=null : !this.getValue().equals(other.getValue())) returnfalse;
returntrue;
    }
@OverridepublicinthashCode() {
finalintPRIME=59;
intresult=1;
result= (result*PRIME) + (this.getName() ==null?43 : this.getName().hashCode());
result= (result*PRIME) + (this.getValue() ==null?43 : this.getValue().hashCode());
returnresult;
    }
  }
}



8)@SneakyThrows这个注解用在方法上,可以将方法中的代码用try-catch语句包裹起来,捕获异常并在catch中用Lombok.sneakyThrow(e)把异常抛出,可以使用@SneakyThrows(Exception.class)的形式指定抛出哪种异常,很简单的注解,直接看个例子:

publicclassSneakyThrowsimplementsRunnable {
@SneakyThrows(UnsupportedEncodingException.class)
publicStringutf8ToString(byte[] bytes) {
returnnewString(bytes, "UTF-8");
    }
@SneakyThrowspublicvoidrun() {
thrownewThrowable();
    }
}


实际效果相当于:


publicclassSneakyThrowsimplementsRunnable {
publicStringutf8ToString(byte[] bytes) {
try{
returnnewString(bytes, "UTF-8");
        }catch(UnsupportedEncodingExceptionuee){
throwLombok.sneakyThrow(uee);
        }
    }
publicvoidrun() {
try{
thrownewThrowable();
        }catch(Throwablet){
throwLombok.sneakyThrow(t);
        }
    }
}


9)@Synchronized这个注解用在类方法或者实例方法上,效果和synchronized关键字相同,区别在于锁对象不同,对于类方法和实例方法,synchronized关键字的锁对象分别是类的class对象和this对象,而@Synchronized得锁对象分别是私有静态final对象LOCK和私有final对象lock,当然,也可以自己指定锁对象,例子也很简单:


publicclassSynchronized {
privatefinalObjectreadLock=newObject();
@Synchronizedpublicstaticvoidhello() {
System.out.println("world");
    }
@SynchronizedpublicintanswerToLife() {
return42;
    }
@Synchronized("readLock")
publicvoidfoo() {
System.out.println("bar");
    }
}



实际效果相当于:


publicclassSynchronized {
privatestaticfinalObject$LOCK=newObject[0];
privatefinalObject$lock=newObject[0];
privatefinalObjectreadLock=newObject();
publicstaticvoidhello() {
synchronized($LOCK) {
System.out.println("world");
     }
   }
publicintanswerToLife() {
synchronized($lock) {
return42;
     }
   }
publicvoidfoo() {
synchronized(readLock) {
System.out.println("bar");
     }
   }
 }



10)@Log这个注解用在类上,可以省去从日志工厂生成日志对象这一步,直接进行日志记录,具体注解根据日志工具的不同而不同,同时,可以在注解中使用topic来指定生成log对象时的类名。不同的日志注解总结如下(上面是注解,下面是实际作用):

@CommonsLogprivatestaticfinalorg.apache.commons.logging.Loglog=org.apache.commons.logging.LogFactory.getLog(LogExample.class);
@JBossLogprivatestaticfinalorg.jboss.logging.Loggerlog=org.jboss.logging.Logger.getLogger(LogExample.class);
@Logprivatestaticfinaljava.util.logging.Loggerlog=java.util.logging.Logger.getLogger(LogExample.class.getName());
@Log4jprivatestaticfinalorg.apache.log4j.Loggerlog=org.apache.log4j.Logger.getLogger(LogExample.class);
@Log4j2privatestaticfinalorg.apache.logging.log4j.Loggerlog=org.apache.logging.log4j.LogManager.getLogger(LogExample.class);
@Slf4jprivatestaticfinalorg.slf4j.Loggerlog=org.slf4j.LoggerFactory.getLogger(LogExample.class);
@XSlf4jprivatestaticfinalorg.slf4j.ext.XLoggerlog=org.slf4j.ext.XLoggerFactory.getXLogger(LogExample.class);


相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
17天前
|
JavaScript NoSQL Java
接替此文【下篇-服务端+后台管理】优雅草蜻蜓z系统JAVA版暗影版为例-【蜻蜓z系列通用】-2025年全新项目整合搭建方式-这是独立吃透代码以后首次改变-独立PC版本vue版搭建教程-优雅草卓伊凡
接替此文【下篇-服务端+后台管理】优雅草蜻蜓z系统JAVA版暗影版为例-【蜻蜓z系列通用】-2025年全新项目整合搭建方式-这是独立吃透代码以后首次改变-独立PC版本vue版搭建教程-优雅草卓伊凡
165 96
接替此文【下篇-服务端+后台管理】优雅草蜻蜓z系统JAVA版暗影版为例-【蜻蜓z系列通用】-2025年全新项目整合搭建方式-这是独立吃透代码以后首次改变-独立PC版本vue版搭建教程-优雅草卓伊凡
|
2天前
|
存储 监控 Java
【Java并发】【线程池】带你从0-1入门线程池
欢迎来到我的技术博客!我是一名热爱编程的开发者,梦想是编写高端CRUD应用。2025年我正在沉淀中,博客更新速度加快,期待与你一起成长。 线程池是一种复用线程资源的机制,通过预先创建一定数量的线程并管理其生命周期,避免频繁创建/销毁线程带来的性能开销。它解决了线程创建成本高、资源耗尽风险、响应速度慢和任务执行缺乏管理等问题。
90 60
【Java并发】【线程池】带你从0-1入门线程池
|
1月前
|
消息中间件 Java 数据库
自研Java框架 Sunrays-Framework使用教程「博客之星」
### Sunrays-Framework:助力高效开发的Java微服务框架 **Sunrays-Framework** 是一款基于 Spring Boot 构建的高效微服务开发框架,深度融合了 Spring Cloud 生态中的核心技术组件。它旨在简化数据访问、缓存管理、消息队列、文件存储等常见开发任务,帮助开发者快速构建高质量的企业级应用。 #### 核心功能 - **MyBatis-Plus**:简化数据访问层开发,提供强大的 CRUD 操作和分页功能。 - **Redis**:实现高性能缓存和分布式锁,提升系统响应速度。 - **RabbitMQ**:可靠的消息队列支持,适用于异步
自研Java框架 Sunrays-Framework使用教程「博客之星」
|
1月前
|
自然语言处理 Java
Java中的字符集编码入门-增补字符(转载)
本文探讨Java对Unicode的支持及其发展历程。文章详细解析了Unicode字符集的结构,包括基本多语言面(BMP)和增补字符的表示方法,以及UTF-16编码中surrogate pair的使用。同时介绍了代码点和代码单元的概念,并解释了UTF-8的编码规则及其兼容性。
113 60
|
1月前
|
Java 数据库连接 数据处理
探究Java异常处理【保姆级教程】
Java 异常处理是确保程序稳健运行的关键机制。它通过捕获和处理运行时错误,避免程序崩溃。Java 的异常体系以 `Throwable` 为基础,分为 `Error` 和 `Exception`。前者表示严重错误,后者可细分为受检和非受检异常。常见的异常处理方式包括 `try-catch-finally`、`throws` 和 `throw` 关键字。此外,还可以自定义异常类以满足特定需求。最佳实践包括捕获具体异常、合理使用 `finally` 块和谨慎抛出异常。掌握这些技巧能显著提升程序的健壮性和可靠性。
50 4
|
1月前
|
存储 移动开发 算法
【潜意识Java】Java基础教程:从零开始的学习之旅
本文介绍了 Java 编程语言的基础知识,涵盖从简介、程序结构到面向对象编程的核心概念。首先,Java 是一种高级、跨平台的面向对象语言,支持“一次编写,到处运行”。接着,文章详细讲解了 Java 程序的基本结构,包括包声明、导入语句、类声明和 main 方法。随后,深入探讨了基础语法,如数据类型、变量、控制结构、方法和数组。此外,还介绍了面向对象编程的关键概念,例如类与对象、继承和多态。最后,针对常见的编程错误提供了调试技巧,并总结了学习 Java 的重要性和方法。适合初学者逐步掌握 Java 编程。
56 1
|
2月前
|
移动开发 前端开发 Java
Java最新图形化界面开发技术——JavaFx教程(含UI控件用法介绍、属性绑定、事件监听、FXML)
JavaFX是Java的下一代图形用户界面工具包。JavaFX是一组图形和媒体API,我们可以用它们来创建和部署富客户端应用程序。 JavaFX允许开发人员快速构建丰富的跨平台应用程序,允许开发人员在单个编程接口中组合图形,动画和UI控件。本文详细介绍了JavaFx的常见用法,相信读完本教程你一定有所收获!
1849 2
Java最新图形化界面开发技术——JavaFx教程(含UI控件用法介绍、属性绑定、事件监听、FXML)
|
2月前
|
NoSQL Java 关系型数据库
Liunx部署java项目Tomcat、Redis、Mysql教程
本文详细介绍了如何在 Linux 服务器上安装和配置 Tomcat、MySQL 和 Redis,并部署 Java 项目。通过这些步骤,您可以搭建一个高效稳定的 Java 应用运行环境。希望本文能为您在实际操作中提供有价值的参考。
203 26
|
1月前
|
前端开发 Java 开发工具
Git使用教程-将idea本地Java等文件配置到gitte上【保姆级教程】
本内容详细介绍了使用Git进行版本控制的全过程,涵盖从本地仓库创建到远程仓库配置,以及最终推送代码至远程仓库的步骤。
44 0
|
IDE Java API
Lombok:让JAVA代码更优雅
Lombok:让JAVA代码更优雅
119 0
Lombok:让JAVA代码更优雅

热门文章

最新文章