使java代码更干净_java如何使用Lombok更优雅地编码

Lombok简介

和其他语言相比,Java经常因为不必要的冗长被批评。Lombok提供了一系列注解用以在后台生成模板代码,将其从你的类中删除,从而有助于保持你的代码整洁。较少的模板意味着更简洁的代码,更易于阅读和维护。在本文中,我将涉及我经常使用的Lombok功能,并想你展示如何使用他们生产更清晰、更简洁的代码。

1.局部变量类型推断:val 和 var

许多语言通过查看等号右侧的表达式来推断局部变量类型。尽管现在Java 10+已经支持这种功能,但在之前的版本中没有Lombok的帮助就无法实现。下面的代码段展示了如何显式指定局部类型:

final Map map = new HashMap<>();

map.put("Joe", 21);

在Lombok中,我们可以通过使用val来缩短它,如下所示:

val valMap = new HashMap();

valMap.put("Sam", 30);

注意,val在背后创建了一个final且不可变的变量。如果你需要一个可变本地变量,可以使用var。

2.@NonNull

对方法参数进行null检查通常不是一个坏主意,特别是如果该方法形成的API被其他开发者使用。虽然这些检查很简单,但是他们可能变得冗长,特别是当你有多个参数时。如下所示,额外的代码无助于可读性,并且可能从方法的主要目的分散注意力。

public void nonNullDemo(Employee employee, Account account) {

if(employee == null) {

throw new IllegalArgumentException("Employee is marked @NonNull but is null");

}

if(account == null) {

throw new IllegalArgumentException("Account is marked @NonNull but is null");

}

// do stuff

}

理想情况下,你需要null检查——没有干扰的那种。这就是@NonNull发挥作用的地方。通过用@NonNull标记参数,Lombok替你为该参数生成null检查。你的方法突然变得更加简洁,但没有丢失那些安全性的null检查。

public void nonNullDemo(@NonNull Employee employee, @NonNull Account account) {

// just do stuff

}

默认情况下,Lombok会抛出NullPointerException,如果你愿意,可以配置 Lombok抛出IllegalArgumentException。我个人更喜欢IllegalArgumentException,因为我认为它更适合于对参数检查。

##3.更简洁的数据类 数据类是Lombok真正有助于减少模板代码的领域。在查看该选项前,思考一下我们经常需要处理的模板种类。数据类通常包括以下一种或全部:

构造函数(有或没有参数)

私有成员变量的 getter 方法

私有非 final 成员变量的 setter 方法

帮助记录日志的 toString 方法

equals 和 hashCode(处理相等/集合)

可以通过 IDE 生成以上内容,因此问题不在于编写他们花费的时间。问题是带有少量成员变量的简单类很快会变得非常冗长。让我们看看Lombok如何通过处理上述的每一项来减少混乱。

3.1. @Getter 和 @Setter

想想下面的Car类。当生成getter和setter时,我们会得到接近 50 行代码来描述一个包含 5 个成员变量的类。

public class Car {

private String make;

private String model;

private String bodyType;

private int yearOfManufacture;

private int cubicCapacity;

public String getMake() {

return make;

}

public void setMake(String make) {

this.make = make;

}

public String getModel() {

return model;

}

public void setModel(String model) {

this.model = model;

}

public String getBodyType() {

return bodyType;

}

public void setBodyType(String bodyType) {

this.bodyType = bodyType;

}

public int getYearOfManufacture() {

return yearOfManufacture;

}

public void setYearOfManufacture(int yearOfManufacture) {

this.yearOfManufacture = yearOfManufacture;

}

public int getCubicCapacity() {

return cubicCapacity;

}

public void setCubicCapacity(int cubicCapacity) {

this.cubicCapacity = cubicCapacity;

}

}

Lombok可以替你生成getter和setter模板。通过对每个成员变量使用 @Getter和@Setter注解,你最终得到一个等效的类,如下所示:

public class Car {

@Getter @Setter

private String make;

@Getter @Setter

private String model;

@Getter @Setter

private String bodyType;

@Getter @Setter

private int yearOfManufacture;

@Getter @Setter

private int cubicCapacity;

}

注意,你可以在非final成员变量上只使用@Setter。在final成员变量上使用它将导致编译错误。

如果你需要为每个成员变量生成getter和setter,你也可以在类级别使用 @Getter和@Setter,如下所示。

@Getter

@Setter

public class Car {

private String make;

private String model;

private String bodyType;

private int yearOfManufacture;

private int cubicCapacity;

}

3.2. @AllArgsConstructor

数据类通常包含一个构造函数,它为每个成员变量接受参数。IDE 为Car生成的构造函数如下所示:

public class Car {

@Getter @Setter

private String make;

@Getter @Setter

private String model;

@Getter @Setter

private String bodyType;

@Getter @Setter

private int yearOfManufacture;

@Getter @Setter

private int cubicCapacity;

public Car(String make, String model, String bodyType, int yearOfManufacture, int cubicCapacity) {

super();

this.make = make;

this.model = model;

this.bodyType = bodyType;

this.yearOfManufacture = yearOfManufacture;

this.cubicCapacity = cubicCapacity;

}

}

我们可以使用@AllArgsConstructor注解实现同样功能。@Getter和 @Setter、@AllArgsConstructor减少模板,保持类更干净且更简洁。

@AllArgsConstructor

public class Car {

@Getter @Setter

private String make;

@Getter @Setter

private String model;

@Getter @Setter

private String bodyType;

@Getter @Setter

private int yearOfManufacture;

@Getter @Setter

private int cubicCapacity;

}

还有其他选项用于生成构造函数。@RequiredArgsConstructor将创建带有每个 final成员变量参数的构造函数,@NoArgsConstructor将创建没有参数的构造函数。

3.3. @ToString

在你的数据类上覆盖toString方法是有助于记录日志的良好实践。IDE 为Car类生成的toString方法如下所示:

@AllArgsConstructor

public class Car {

@Getter @Setter

private String make;

@Getter @Setter

private String model;

@Getter @Setter

private String bodyType;

@Getter @Setter

private int yearOfManufacture;

@Getter @Setter

private int cubicCapacity;

@Override

public String toString() {

return "Car [make=" + make + ", model=" + model + ", bodyType=" + bodyType + ", yearOfManufacture="

+ yearOfManufacture + ", cubicCapacity=" + cubicCapacity + "]";

}

}

我们可以使用ToString注解废除这个,如下所示:

@ToString

@AllArgsConstructor

public class Car {

@Getter @Setter

private String make;

@Getter @Setter

private String model;

@Getter @Setter

private String bodyType;

@Getter @Setter

private int yearOfManufacture;

@Getter @Setter

private int cubicCapacity;

}

默认情况下,Lombok生成包含所有成员变量的toString方法。可以通过 exclude属性@ToString(exclude={"someField"}, "someOtherField"}) 覆盖行为将某些成员变量排除。

3.4. @EqualsAndHashCode

如果你正在将你的数据类和任何类型的对象比较,则需要覆盖equals和hashCode 方法。对象的相等是基于业务规则定义的。举个例子,在Car类中,如果两个对象有相同的make、model和bodyType,我可能认为他们是相等的。如果我使用 IDE 生成equals方法检查make、model和bodyType,它看起来会是这样:

@Override

public boolean equals(Object obj) {

if (this == obj)

return true;

if (obj == null)

return false;

if (getClass() != obj.getClass())

return false;

Car other = (Car) obj;

if (bodyType == null) {

if (other.bodyType != null)

return false;

} else if (!bodyType.equals(other.bodyType))

return false;

if (make == null) {

if (other.make != null)

return false;

} else if (!make.equals(other.make))

return false;

if (model == null) {

if (other.model != null)

return false;

} else if (!model.equals(other.model))

return false;

return true;

}

等价的hashCode实现如下所示:

@Override

public int hashCode() {

final int prime = 31;

int result = 1;

result = prime * result + ((bodyType == null) ? 0 : bodyType.hashCode());

result = prime * result + ((make == null) ? 0 : make.hashCode());

result = prime * result + ((model == null) ? 0 : model.hashCode());

return result;

}

虽然 IDE 处理了繁重的工作,但我们在类中仍然有大量的模板代码。Lombok允许我们使用@EqualsAndHashCode类注解实现相同的功能,如下所示:

@ToString

@AllArgsConstructor

@EqualsAndHashCode(exclude = { "yearOfManufacture", "cubicCapacity" })

public class Car {

@Getter @Setter

private String make;

@Getter @Setter

private String model;

@Getter @Setter

private String bodyType;

@Getter @Setter

private int yearOfManufacture;

@Getter @Setter

private int cubicCapacity;

}

默认情况下,@EqualsAndHashCode会创建包含所有成员变量的equals和 hashCode方法。exclude选项可用于通知Lombok排除某些成员变量。

在上面的代码片段中。我已经从生成的equals和hashCode方法中排除了 yearOfManuFacture 和cubicCapacity。

3.5. @Data

如果你想使数据类尽可能精简,可以使用@Data注解。@Data 是@Getter、@Setter、@ToString、@EqualsAndHashCode 和 @RequiredArgsConstructor 的快捷方式。

@ToString

@RequiredArgsConstructor

@EqualsAndHashCode(exclude = { "yearOfManufacture", "cubicCapacity" })

public class Car {

@Getter @Setter

private String make;

@Getter @Setter

private String model;

@Getter @Setter

private String bodyType;

@Getter @Setter

private int yearOfManufacture;

@Getter @Setter

private int cubicCapacity;

}

通过使用@Data,我们可以将上面的类精简如下:

@Data

public class Car {

private String make;

private String model;

private String bodyType;

private int yearOfManufacture;

private int cubicCapacity;

}

4. 使用 @Buidler 创建对象

建造者设计模式描述了一种灵活的创建对象的方式。Lombok可以帮你轻松的实现该模式。看一个使用简单Car类的示例。假设我们希望可以创建各种Car对象,但我们希望在创建时设置的属性具有灵活性。

@AllArgsConstructor

public class Car {

private String make;

private String model;

private String bodyType;

private int yearOfManufacture;

private int cubicCapacity;

private List serviceDate;

}

假设我们要创建一个Car,但只想设置make和model。在Car上使用标准的全参数构造函数意味着我们只提供make和model并设置其他参数为null。

Car2 car2 = new Car2("Ford", "Mustang", null, null, null, null);

这可行但并不理想,我们必须为我们不感兴趣的参数传递null。我们可以创建一个只接受make和model的构造函数来避开这个问题。这是一个合理的解决方法,但不够灵活。如果我们有许多不同的字段排列,我们可以用什么来创建一个新Car?最终我们得到了一堆不同的构造函数,代表了我们可以实例化Car的所有可能方式。

解决该问题的一种干净、灵活的方式是使用建造者模式。Lombok通过@Builder 注解帮你实现建造者模式。当你使用@Builder注解Car类时,Lombok会执行以下操作:

添加一个私有构造函数到Car

创建一个静态的CarBuilder类

在CarBuilder中为Car中的每个成员创建一个setter风格方法。

在CarBuilder中添加创建Car的新实例的建造方法。

CarBuilder上的每个setter风格方法返回自身的实例(CarBuilder)。这允许你进行方法链式调用并为对象创建提供流畅的 API。让我们看看它如何使用。

Car muscleCar = Car.builder().make("Ford")

.model("mustang")

.bodyType("coupe")

.build();

现在只使用make和model创建Car比之前更简洁了。只需在Car上简单的调用生成的builder方法获取CarBuilder实例,然后调用任何我们感兴趣的setter风格方法。最后,调用build创建Car的新实例。

另一个值得一提的方便的注解是@Singular。默认情况下,Lombok 为集合创建使用集合参数的标准的 setter 风格方法。在下面的例子中,我们创建了新的 Car并设置了服务日期列表。

Car muscleCar = Car.builder().make("Ford")

.model("mustang")

.serviceDate(Arrays.asList(LocalDate.of(2016, 5, 4)))

.build();

向集合成员变量添加@Singular将提供一个额外的方法,允许你向集合添加单个项。

@Builder

public class Car {

private String make;

private String model;

private String bodyType;

private int yearOfManufacture;

private int cubicCapacity;

@Singular

private List serviceDate;

}

现在我们可以添加单个服务日期,如下所示:

Car muscleCar3 = Car.builder()

.make("Ford")

.model("mustang")

.serviceDate(LocalDate.of(2016, 5, 4))

.build();

这是一个有助于在创建对象期间处理集合时保持代码简洁的快捷方法。

5.日志

Lombok另一个伟大的功能是日志记录器。如果没有Lombok,要实例化标准的 SLF4J日志记录器,通常会有以下内容:

public class SomeService {

private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LogExample.class);

public void doStuff(){

log.debug("doing stuff....");

}

}

这些日志记录器很沉重,并为每个需要日志记录的类添加了不必要的混乱。值得庆幸的是 Lombok提供了一个为你创建日志记录器的注解。你要做的所有事情就是在类上添加注解,这样就可以了。

@Slf4j

public class SomeService {

public void doStuff(){

log.debug("doing stuff....");

}

}

我在这里使用了@SLF4J注解,但Lombok能为几乎所有通用Java日志框架生成日志记录器。有关更多日志记录器的选项,请参阅文档。

6.Lombok给你控制权

我非常喜欢Lombok的一点是它的不侵入性。。如果你决定在使用如@Getter、@Setter 或 @ToString时也想要自己的方法实现,你的方法将总是优先于 Lombok。它允许你在大多数时间使用Lombok,但在你需要的时候仍有控制权。

7.写得更少,做得更多

在过去的 4 到 5 年里,我几乎在每个项目中都使用了Lombok。我喜欢它,因为它减少了杂乱,最终得到了更干净、更简洁、更易阅读的代码。它不一定为你节省大量时间,因为它生成的代码可以由 IDE 自动生成。话虽如此,我认为更干净的代码的好处不仅仅是将其添加到Java堆栈中。

8. 延展阅读

我已经介绍了我经常使用的Lombok功能,但还有很多我没有讲到。如果你喜欢目前为止所看到的,并希望了解更多,请继续阅读 Lombok 文档。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/527001.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java自动创建月份_使用Java根据月份动态绘制BarGraph

您需要通过每次更改来更新数据集.我添加了一个updateDataset()方法,并在几个关键位置调用了它.private void updateDataset() {dataset.clear();for (int i 1; i < finalday; i) {dataset.setValue(i, "Marks", "" i);}笔记&#xff1a;>不要使用绝…

mysql 5.6.23 源码包安装报错_Ubuntu 14.10下编译安装MySQL 5.6.23

1. 安装环境&#xff1a;Ubuntu Server 14.10MySQL-5.6.23.tar.gz2. 安装必备的工具sudo apt-get install make bison g build-essential libncurses5-dev cmake3. 添加组合用户 设置安装目录权限sudo groupadd mysqlsudo useradd –g mysql mysql –s /bin/false #创建用户mys…

java 阻塞 性能_聊聊并发-Java中的阻塞队列

1. 什么是阻塞队列&#xff1f;阻塞队列(BlockingQueue)是一个支持两个附加操作的队列。这两个附加的操作是&#xff1a;在队列为空时&#xff0c;获取元素的线程会等待队列变为非空。当队列满时&#xff0c;存储元素的线程会等待队列可用。阻塞队列常用于生产者和消费者的场景…

java编译器对代码的优化_使用最终局部变量的Java编译器优化

我一直认为final关键字对局部方法变量或参数没有影响。因此,我尝试测试以下代码,但似乎我错了:private static String doStuffFinal() {final String a "A";final String b "B";final int n 2;return a b n;}private static String doStuffNotFinal()…

友盟统计java代码_SFAnalytics 分析友盟统计源码,反编译 SDK,还有部分没有 出来 android 259万源代码下载- www.pudn.com...

文件名称: SFAnalytics下载 收藏√ [5 4 3 2 1 ]开发工具: Java文件大小: 8023 KB上传时间: 2016-06-05下载次数: 0提 供 者: 花心大萝卜详细说明&#xff1a;分析友盟统计源码&#xff0c;反编译友盟统计SDK&#xff0c;还有部分没有反编译出来-Analysis their Allies s…

Java导入sql失败_java – 在hibernate中导入import.sql失败

我希望每次应用程序运行时自动删除表并创建一个新表,并自动插入预定义数据.我已经在import.sql中准备数据了.我已经在application.properties中设置了spring.jpa.hibernate.ddl-auto create-drop.但是,为什么我会收到以下错误&#xff1f;我可以手动插入它.2015-11-20 20:53:5…

java mvc数据库 封装_关于SpringMvc参数封装_JavaEE框架(Maven+SpringMvc+Spring+MyBatis)全程实战教程_Java视频-51CTO学院...

SpringMVCSpring MVC属于SpringFrameWork的后续产品&#xff0c;已经融合在Spring Web Flow里面。Spring MVC 分离了控制器、模型对象、分派器以及处理程序对象的角色&#xff0c;这种分离让它们更容易进行定制。SpringSpring是一个开源框架&#xff0c;Spring是于2003 年兴起的…

Java语言有哪几种访问权限_java基础之java四种访问权限详解

引言Java中的访问权限理解起来不难&#xff0c;但完全掌握却不容易&#xff0c;特别是4种访问权限并不是任何时候都可以使用。下面整理一下&#xff0c;在什么情况下&#xff0c;有哪些访问权限可以允许选择。一、访问权限简介访问权限控制&#xff1a; 指的是本类及本类内部的…

centos 使用java_如何在CentOS 8上安装Java

Java是用于构建不同类型的应用程序和系统的最流行的编程语言之一。Java有两种不同的实现&#xff0c;OpenJDK和Oracle Java&#xff0c;两者之间几乎没有区别&#xff0c;只是Oracle Java具有一些其他的商业功能。 Oracle Java License仅允许该软件的非商业使用&#xff0c;例如…

kafka java客户端加密_kafka消息加密(SASL/PLAIN)

kafka消息加密(SASL/PLAIN)具体的配置方式官网已经说的很清楚了(尽量去官网看)官网配置分为以下几个步骤1、 在conf文件目录下添加文件kafka_server_jaas.conf(文件目录 文件名随意)内容如下KafkaServer {org.apache.kafka.common.security.plain.PlainLoginModule requireduse…

oracle查询本月第一天_oracle获取本月第一天和最后一天及Oracle trunc()函数的用法...

select to_char(trunc(add_months(last_day(sysdate), -1) 1), yyyy-mm-dd) "本月第一天", to_char(last_day(sysdate), yyyy-mm-dd) "本月最后一天" --Oracle trunc()函数的用法 /**************日期********************/ 1.select trunc(sysdate) …

20199计算机二级java答案_计算机二级Java练习题-2019.9

是不是急于做大量的计算机等级考试题库&#xff0c;却因测试结果不尽人意而心慌不安&#xff1f;不要急&#xff01;考无忧小编为大家准备了一些二级Java练习题&#xff0c;希望能帮助大家高效复习&#xff0c;轻松通关&#xff01;1.下列叙述中正确的是()。A.栈是“先进先出”…

java处理请求的流程_Java Spring mvc请求处理流程详解

Spring mvc请求处理流程详解前言spring mvc框架相信很多人都很熟悉了&#xff0c;关于这方面的资料也是一搜一大把。但是感觉讲的都不是很细致&#xff0c;让很多初学者都云里雾里的。本人也是这样&#xff0c;之前研究过&#xff0c;但是后面一段时间不用发现又忘记了。所以决…

php之二叉树,数据结构之二叉树——链式存储结构(php代码实现)

/*** ClearBiTree() 清空二叉树* CreateBiTree() 创建二叉树* BiTreeEmpty() 判断二叉树是否为空* BiTreeDepth() 返回二叉树的深度* root() 返回二叉树的根* Parent() 返回给定元素的双亲* LeftChild() 要返回左孩子的元素* RightChild() 要返回右孩子的元素* LeftSibling() 要…

php 面向对象 特性,PHP面向对象三大特点学习

PHP面向对象三大特点学习class B extends A{public function __construct(){//两种方法都行A::test();parent::test();}}$bnew B();5、如果一个子类(派生类)的方法与父类的方法完全一样时(public&#xff0c;protected)&#xff0c;我们称为方法覆盖或方法重写(override)&#…

云虚机php.ini在,虚拟主机php.ini在哪

虚拟主机php.ini在哪&#xff1f;虚拟主机php.ini文件一般放置在文件管理器的“others”文件夹中。php.ini文件控制了PHP很多方面的性能和行为&#xff0c;且必须命名为“php.ini”。PHP.ini文件部分配置指令简短说明&#xff1a;short_open_tag boolean决定是否允许使用 PHP 代…

robust off matlab,matlab_robust LM test 求指点!(空间计量)

空间计量软件包中的示例命令&#xff1a;trtrace((WW)*W);[N junk]size(W);[nobs k]size(x);Tnobs/N;betaresults.beta;resresults.resid;sigeres*res/nobs;WXB20;EWE0;EWY0;xpxix*x\eye(k);WXBkron(speye(T),W)*x*beta;MWXB(speye(N*T)-x*xpxi*x)*WXB;WXB2WXB*MWXB;for t1:Tt1…

2019matlab中的floyd,基于matlab的floyd算法详解

function [d,path]floyd(a,sp,ep)% floyd - 最短路问题%% Syntax: [d,path]floyd(a,sp,ep)%% Inputs:% a - 距离矩阵是指i到j之间的距离&#xff0c;可以是有向的% sp - 起点的标号% ep - 终点的标号%% Outputs:% d - 最短路的距离% path - 最短路的…

.1 matlab,1 MATLAB集成环境

启动MATLAB后&#xff0c;将进入MATLAB集成环境。MATLAB集成环境包括MATLAB主窗口、命令窗口(Command Window)、工作空间窗口(Workspace)、命令历史窗口(Command History)、当前目录窗口(Current Directory)和启动平台窗口(Launch Pad)。一、命令窗口命令窗口是MATLAB的主要交互…

matlab 读取mov文件格式,VideoReader 支持的文件格式 - MATLAB VideoReader.getFileFormats - MathWorks 中国...

获取受支持的文件格式。formats VideoReader.getFileFormats()Video File Formats:.asf - ASF File.asx - ASX File.avi - AVI File.m4v - MPEG-4 Video.mj2 - Motion JPEG2000.mov - QuickTime movie.mp4 - MPEG-4.mpg - MPEG-1.wmv - Windows Media Video此输出适用于 Windo…