当前位置: 首页 > news >正文

谨慎使用Lombok的@Builder注解

现在很多程序员都习惯使用Lombok来使代码更加 “简洁”。但是使用Lombok也会造成很多问题,尤其@Builder 有个很大的坑,已经见过好几次由于使用@Builder注解导致默认值失效的问题,如果测试时没有在意这个问题,就很容易引发线上问题。

问题复现

我们随便定义一个类Config,对其中两个属性设置默认值。

import lombok.Builder;
import lombok.Data;@Data
@Builder
public class Config {private boolean isOpen = true;private String name;private int value = 20;
}public class LombokDemo {public static void main(String[] args) {Config config = Config.builder().name("test").build();System.out.println(config);}
}

借助Builder模式创建Config类实例时,仅设置name属性,然后打印出实例

public class LombokDemo {public static void main(String[] args) {Config config = Config.builder().name("test").build();System.out.println(config);}
}

输出结果如下。

Config(isOpen=false, name=test, value=0)

我们为isOpen及value属性设置的默认值失效了。

原因分析

想了解为什么会这样,我们只需要查看使用Lombok的注解后的Config类的 class文件长啥样就明白了。@Builder通过Lombok的注解处理器,在编译时会自动生成一个静态内部类,这个内部类就是所谓的builder类,它包含了和被注解的类中的属性一一对应的setter方法,并且在build()方法中返回一个被注解的类的对象。这个builder类的代码实现是通过Lombok生成的,所以我们不需要手动编写。


public class Config {private boolean isOpen = true;private String name;private int value = 20;Config(boolean isOpen, String name, int value) {this.isOpen = isOpen;this.name = name;this.value = value;}public static ConfigBuilder builder() {return new ConfigBuilder();}public boolean isOpen() {return this.isOpen;}public String getName() {return this.name;}public int getValue() {return this.value;}public void setOpen(boolean isOpen) {this.isOpen = isOpen;}public void setName(String name) {this.name = name;}public void setValue(int value) {this.value = value;}public boolean equals(Object o) {// 省略}protected boolean canEqual(Object other) {return other instanceof Config;}public int hashCode() {// 省略}public String toString() {return "Config(isOpen=" + this.isOpen() + ", name=" + this.getName() + ", value=" + this.getValue() + ")";}public static class ConfigBuilder {private boolean isOpen;private String name;private int value;ConfigBuilder() {}public ConfigBuilder isOpen(boolean isOpen) {this.isOpen = isOpen;return this;}public ConfigBuilder name(String name) {this.name = name;return this;}public ConfigBuilder value(int value) {this.value = value;return this;}public Config build() {return new Config(this.isOpen, this.name, this.value);}public String toString() {return "Config.ConfigBuilder(isOpen=" + this.isOpen + ", name=" + this.name + ", value=" + this.value + ")";}}
}

可以看到,ConfigBuilder中isOpen和value属性并没有使用我们想要设置的默认值。调用build方法时, ConfigBuilder会调用全参的构造方法来构造Config 对象。

解决方法

使用@Builder.Default注解来标识带默认值的属性

import lombok.Builder;
import lombok.Data;@Data
@Builder
public class SomeConfig {@Builder.Defaultprivate boolean isOpen = true;private String name;@Builder.Defaultprivate int value = 20;
}

修改后输出结果如下

Config(isOpen=true, name=test, value=20)

为什么加了@Builder.Default注解就能解决问题呢,看一下编译后的class文件就明白了

public class Config {private boolean isOpen;private String name;private int value;private static boolean $default$isOpen() {return true;}private static int $default$value() {return 20;}Config(boolean isOpen, String name, int value) {this.isOpen = isOpen;this.name = name;this.value = value;}public static ConfigBuilder builder() {return new ConfigBuilder();}public boolean isOpen() {return this.isOpen;}public String getName() {return this.name;}public int getValue() {return this.value;}public void setOpen(boolean isOpen) {this.isOpen = isOpen;}public void setName(String name) {this.name = name;}public void setValue(int value) {this.value = value;}public boolean equals(Object o) {// 省略}protected boolean canEqual(Object other) {return other instanceof Config;}public int hashCode() {// 省略}public String toString() {boolean var10000 = this.isOpen();return "Config(isOpen=" + var10000 + ", name=" + this.getName() + ", value=" + this.getValue() + ")";}public static class ConfigBuilder {private boolean isOpen$set;private boolean isOpen$value;private String name;private boolean value$set;private int value$value;ConfigBuilder() {}public ConfigBuilder isOpen(boolean isOpen) {this.isOpen$value = isOpen;this.isOpen$set = true;return this;}public ConfigBuilder name(String name) {this.name = name;return this;}public ConfigBuilder value(int value) {this.value$value = value;this.value$set = true;return this;}public Config build() {boolean isOpen$value = this.isOpen$value;if (!this.isOpen$set) {isOpen$value = Config.$default$isOpen();}int value$value = this.value$value;if (!this.value$set) {value$value = Config.$default$value();}return new Config(isOpen$value, this.name, value$value);}public String toString() {return "Config.ConfigBuilder(isOpen$value=" + this.isOpen$value + ", name=" + this.name + ", value$value=" + this.value$value + ")";}}
}

每个设置默认值的属性都会在Builder中加上是否设置的标记,如果没有主动设置值,则调用Config中的默认值的静态方法进行赋值,然后再调用Config全参构造方法构造该对象。

使用@Builder注解的缺点

  1. 如果在类上使用了@Builder 注解,那么你需要手动添加一个无参构造函数,否则有些序列化框架需要通过newInstance构造对象时会报错。
  2. 如果在类上使用了@Builder注解,就不能再在构造函数或方法上使用 @Builder注解,否则会导致重复生成构造器类
  3. 如果在类上使用了@Builder 注解,想给某个属性设置一个默认值,还需要在属性上使用@Builder.Default 注解,否则默认值会被忽略。
  4. 如果想让子类继承父类的属性,那么你需要在子类的全参构造函数上使用 @Builder注解,并且在父类上使用@AllArgsConstructor注解,否则子类的构造器类不会包含父类的属性

相关文章:

谨慎使用Lombok的@Builder注解

现在很多程序员都习惯使用Lombok来使代码更加 “简洁”。但是使用Lombok也会造成很多问题,尤其Builder 有个很大的坑,已经见过好几次由于使用Builder注解导致默认值失效的问题,如果测试时没有在意这个问题,就很容易引发线上问题。…...

leetcode455. 分发饼干 【贪心】

题目: 假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。 对每个孩子 i,都有一个胃口值 g[i],这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 j&#xff0c…...

4V-28V Vin,6A同步降压DCDC变换器,集成3.3V和150mA LDO——SCT2361FPBR

SCT2361是一种高效率的同步降压型DC-DC变换器,集成3.3V和150mA LDO。输入电压范围为4V-28V,输出电压可调为0.6V,具有3mmx3mm的小QFN封装,可提供连续6A的输出电流。该器件将高、低压侧功率mosfet集成,使导通损耗降到最低…...

Linux中的scp指令

在Linux和Unix系统中,scp(Secure Copy Protocol)是一个用于通过SSH协议进行安全文件传输的命令行实用程序。与传统的cp(copy)命令不同,scp允许用户在不同的机器之间、或同一台机器的不同位置之间传输文件或…...

剑指 Offer 11. 旋转数组的最小数字

剑指 Offer 11. 旋转数组的最小数字 二分 要注意的是,由于存在重复数字,所以初始状态可能不满足二分的性质。不满足的情况是:左边开始的数字和右边结束的数字相等,所以一开始要缩小右边界,让右边界的数字小于第一个数…...

Redis面试题总结

1.什么是Redis Redis 是一种基于内存的数据库对数据的读写操作都是在内存中完成,因此读写速度非常快,常用于缓存,消息队列、分布式锁等场景。 Redis 提供了多种数据类型来支持不同的业务场景,比如 String(字符串)、Hash(哈希)、…...

【Eclipse】搭建python环境;运行第一个python程序helloword

目录 0.环境 1.需准备&搭建思路 2.搭建具体步骤 1)查看是否安装过python 2)安装eclipse 3)安装和配置pyDev 3.创建第一个python程序具体步骤 1)新建项目 2)输入项目名字,和配置选项 3&#x…...

OpenAI 发布企业版ChatGPT-4

OpenAI 发布企业版ChatGPT-4 ChatGPT Enterprise 版本功能ChatGPT Enterprise 对比ChatGPT Enterprise 不同点未来发布计划OpenAI 发布企业版ChatGPT-4 OpenAI 宣布,鉴于ChatGPT的爆炸性成果,推出了针对企业的 ChatGPT Enterprise 版 ChatGPT Enterprise 版本功能 包含所有…...

Flowable7 设计器

1、flowable7 已经在主版本上移除了Flowable UI相关的包,包含bpm-json相关的所有包和流程设计器相关前端文件。 2、flowable7 版本目前只保留了xml运行相关的包,ui modeler已经移除 3、目前官方给的回复是只能在 flowable 云产品上使用设计器&#xff…...

Flutter问题记录 - Unable to find bundled Java version

新版本的Android Studio真的移除了JRE,jre目录找不到,怪不得报错了,不过多了一个jbr目录,找了个以前的Android Studio版本对比 搜了一下jbr(JetBrains Runtime),原来IDEA老早就开始用了&#xf…...

Tomcat 日志乱码问题解决

我就是三井,一个永不放弃希望的男人。——《灌篮高手》 Tomcat 日志乱码问题解决 乱码原因:字符编码不一致 如:国内电脑一般都是GBK编码,而Tomcat日志使用的是UTF-8编码 解决方法:将对应字符编码由 UTF-8 改为 GBK 即…...

yum源以及rpm安装包配置、yum源冲突、yum-config-manager命令找不到、curl: (35)、docker镜像重复拉取失败

yum源配置并解决冲突、curl: (35)、docker镜像重复拉取失败、yum-config-manager命令找不到的解决方法 有的时候按照教程走,可能会设置yum源,设置后用yum下载东西很有可能或造成冲突 yum源冲突的解决方式无非有两种:1. 删除冲突软…...

ChatGPT和文心一言的优缺点比较

ChatGPT和文心一言都是自然语言生成技术的代表,下面是它们的优缺点比较: ChatGPT的优点: 自由度高:ChatGPT生成的文本与给定的话题没有紧密的关联,可以灵活地生成多种不同的文本。多样性高:ChatGPT可以生…...

⛳ 面试题-单例模式会存在线程安全问题吗?

🎍目录 ⛳ 面试题-单例模式会存在线程安全问题吗?🎨 一、单例模式-简介🚜 二、饿汉式🐾 三、懒汉式🎯 3.1、懒汉式:在调用 getInstance 的时候才创建对象。(线程不安全)&…...

C - 滑动窗口 /【模板】单调队列

Description 有一个长为 n 的序列 a,以及一个大小为 k 的窗口。现在这个从左边开始向右滑动,每次滑动一个单位,求出每次滑动后窗口中的最大值和最小值。 例如: The array is [1,3,−1,−3,5,3,6,7] and k3。 Input 输入一共有…...

工厂人员作业行为动作识别检测算法

工厂人员作业行为动作识别检测算法通过yolov7python深度学习算法框架模型,工厂人员作业行为动作识别检测算法实时识别并分析现场人员操作动作行为是否符合SOP安全规范流程作业标准,如果不符合则立即抓拍告警提醒。Python是一种由Guido van Rossum开发的通…...

【数据结构】顺序表详解

当我们写完通讯录后,顺序表肯定难不倒你,跟着小张一起来学习顺序表吧! 线性表 线性表(linear list)是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结构,常见的线性表&#x…...

HTML 播放器效果

效果图 实现代码 <!DOCTYPE HTML> <html><head><title>爱看动漫社区 | 首页 </title><link href"css/bootstrap.css" relstylesheet typetext/css /><!-- jQuery --><script src"js/jquery-1.11.0.min.js"…...

C++常用23种设计模式总结(三)------装饰模式

往期回顾 C常用23种设计模式总结(一)------单例模式 C常用23种设计模式总结(二)------观察者模式 什么是装饰模式 装饰模式是一种结构型设计模式&#xff0c;它允许你在运行时为对象动态添加新的行为。该模式通过将对象放入包装器中来实现这一点&#xff0c;这个包装器会实现与…...

选择O型圈时要考虑哪些因素?

为您的应用选择正确的O型圈对于确保适当的密封和较佳性能至关重要。O型圈可用的材料和尺寸多种多样&#xff0c;做出正确的选择可能需要知道一些重要的知识点。在本文中&#xff0c;我们将讨论选择O型圈时需要考虑的一些关键因素。 1、材料兼容性&#xff1a;先要考虑的因素是…...

安全管理中心技术测评要求项

1.系统管理-通过系统管理员进行系统管理操作 1-0/2-2/3-2/4-2 a&#xff09;对系统管理员进行身份鉴别&#xff0c;只允许其通过特定的命令或操作界面进行系统管理操作&#xff0c;并对这些操作进行审计 b&#xff09;通过系统管理员对系统的资源和运行进行配置、控制和管理&am…...

Hibernate(Spring Data)抓取策略

文章目录 示例代码放到最后&#xff0c;使用的是Springboot 项目1. 简介2. Hibernate抓取策略分类2.1 即时加载&#xff08;Eager Loading&#xff09;2.2 延迟加载&#xff08;Lazy Loading&#xff09;2.3 子查询加载&#xff08;Subselect Loading&#xff09;2.4 基于批处理…...

【高阶数据结构】map和set的介绍和使用 {关联式容器;键值对;map和set;multimap和multiset;OJ练习}

map和set的介绍和使用 一、关联式容器 关联式容器和序列式容器是C STL中的两种不同类型的容器。 关联式容器是基于键值对的容器&#xff0c;其中每个元素都有一个唯一的键值&#xff0c;可以通过键值来访问元素。关联式容器包括set、multiset、map和multimap。 序列式容器是…...

系统架构技能之设计模式-单件模式

一、开篇 其实我本来不是打算把系统架构中的一些设计模式单独抽出来讲解的&#xff0c;因为很多的好朋友也比较关注这方面的内容&#xff0c;所以我想通过我理解及平时项目中应用到的一 些常见的设计模式,拿出来给大家做个简单讲解&#xff0c;我这里只是抛砖引玉&#xff0c…...

Redis进阶 - JVM进程缓存

原文首更地址&#xff0c;阅读效果更佳&#xff01; Redis进阶 - JVM进程缓存 | CoderMast编程桅杆https://www.codermast.com/database/redis/redis-advance-jvm-process-cache.html 传统缓存的问题 传统的缓存策略一般是请求到达 Tomcat 后&#xff0c;先查询 Redis &…...

SD-WAN带您告别高成本、单一功能和安全性差

现今&#xff0c;随着企业规模不断扩大和分散办公越来越普遍&#xff0c;企业对于网络的需求也变得越来越高。然而&#xff0c;传统的组网方式面临着很多的问题&#xff0c;比如&#xff1a;成本高、功能单一、安全性差等问题。 传统组网方式有哪些&#xff1f; 传统的组网方式…...

面试必备:揭秘ArrayList和LinkedList,区别、优缺点与使用场景

大家好&#xff0c;我是你们的小米&#xff01;今天我要跟大家聊一个在面试中经常被问到的热门话题——ArrayList和LinkedList的区别、优缺点以及它们的使用场景。作为程序员&#xff0c;掌握这些知识点不仅可以在面试中脱颖而出&#xff0c;还能帮助我们更好地在项目中选择合适…...

【局部活动轮廓】使用水平集方法实现局部活动轮廓方法研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…...

Git 同步远程新的同名分支

背景 因为远程分支的提交记录过多&#xff0c;导致本地的commit内容过大&#xff0c;会产生一些问题&#xff1a; 第一次拉取时间较长占用本地和远程的存储 原因 因为项目已有一些年头&#xff0c;若是每次文件提交比较大&#xff0c;那么占用空间就更大 解决方案 该方案…...

PingCode DevOps 团队:企业CICD流水线可能会遇到的问题及解法

CICD 流水线是指一系列自动化的构建、测试和部署步骤&#xff0c;用于将应用程序从开发到生产环境的过程。在 CICD 流水线中&#xff0c;每个步骤都是自动化的&#xff0c;并且在完成后会触发下一个步骤的执行。 CICD 的价值 CICD 流水线可以帮助团队更快地交付产品&#xff…...