都说了布尔类型的变量不要加 is 前缀,非要加,这不是坑我了嘛
开心一刻
今天心情不好,给哥们发语音
我:哥们,晚上出来喝酒聊天吧
哥们:咋啦,心情不好?
我:嗯,刚刚在公交车上看见前女友了
哥们:然后呢?
我:给她让座时,发现她怀孕了...
哥们:所以难受了?
我:不是她怀孕让我难受,是她怀孕还坐公交车让我难受
哥们:不是,她跟着你就不用坐公交车了?不还是也要坐,有区别吗?
我默默的挂断了语音,心情更难受了

Java开发手册
作为一个 javaer,我们肯定看过 Alibaba 的 Java开发手册,作为国内Java开发领域的标杆性编码规范,我们或多或少借鉴了其中的一些规范,其中有一点

我印象特别深,也一直在奉行,自己还从未试过用 is 作为布尔类型变量的前缀,不知道会有什么坑;正好前段时间同事这么用了,很不幸,他挖坑,我踩坑,阿西吧!

is前缀的布尔变量有坑
为了复现问题,我先简单搞个 demo;调用很简单,服务 workflow 通过 openfeign 调用 offline-sync,代码结构如下

qsl-data-govern-common:整个项目的公共模块
qsl-offline-sync:离线同步
- qsl-offline-sync-api:向外提供
openfeign接口- qsl-offline-sync-common:离线同步公共模块
- qsl-offline-sync-server:离线同步服务
qsl-workflow:工作流
- qsl-workflow-api:向外提供
openfeign接口,暂时空实现- qsl-workflow-common:工作流公共模块
- qsl-workflow-server:工作流服务
完整代码:qsl-data-govern
qsl-offline-sync-server 提供删除接口
/**
* @author 青石路
*/
@RestController
@RequestMapping("/task")
public class SyncTaskController {
private static final Logger LOG = LoggerFactory.getLogger(SyncTaskController.class);
@PostMapping("/delete")
public ResultEntity<String> delete(@RequestBody SyncTaskDTO syncTask) {
// TODO 删除处理
LOG.info("删除任务[taskId={}]", syncTask.getTaskId());
return ResultEntity.success("删除成功");
}
}
qsl-offline-sync-api 对外提供 openfeign 接口
/**
* @author 青石路
*/
@FeignClient(name = "data-govern-offline-sync", contextId = "dataGovernOfflineSync", url = "${offline.sync.server.url}")
public interface OfflineSyncApi {
@PostMapping(value = "/task/delete")
ResultEntity<String> deleteTask(@RequestBody SyncTaskDTO syncTaskDTO);
}
qsl-workflow-server 调用 openfeign 接口
/**
* @author 青石路
*/
@RestController
@RequestMapping("/definition")
public class WorkflowController {
private static final Logger LOG = LoggerFactory.getLogger(WorkflowController.class);
@Resource
private OfflineSyncApi offlineSyncApi;
@PostMapping("/delete")
public ResultEntity<String> delete(@RequestBody WorkflowDTO workflow) {
LOG.info("删除工作流[workflowId={}]", workflow.getWorkflowId());
// 1.查询工作流节点,查到离线同步节点(taskId = 1)
// 2.删除工作流节点,删除离线同步节点
ResultEntity<String> syncDeleteResult = offlineSyncApi.deleteTask(new SyncTaskDTO(1L));
if (syncDeleteResult.getCode() != 200) {
LOG.error("删除离线同步任务[taskId={}]失败:{}", 1, syncDeleteResult.getMessage());
ResultEntity.fail(syncDeleteResult.getMessage());
}
return ResultEntity.success("删除成功");
}
}
逻辑是不是很简单?我们启动两个服务,然后发起 http 请求
POST http://localhost:8081/data-govern/workflow/definition/delete
Content-Type: application/json{
"workflowId": 99
}
此时 qsl-offline-sync-server 日志输出如下
2025-06-30 14:53:06.165|INFO|http-nio-8080-exec-4|25|c.q.s.s.controller.SyncTaskController :删除任务[taskId=1]
至此,一切都很正常,第一版也是这么对接的;后面 offline-sync 进行调整,删除接口增加了一个参数:isClearData
public class SyncTaskDTO {
public SyncTaskDTO(){}
public SyncTaskDTO(Long taskId, Boolean isClearCache) {
this.taskId = taskId;
this.isClearData = isClearCache;
}
private Long taskId;
private Boolean isClearData = false;
public Long getTaskId() {
return taskId;
}
public void setTaskId(Long taskId) {
this.taskId = taskId;
}
public Boolean getClearData() {
return isClearData;
}
public void setClearData(Boolean clearData) {
isClearData = clearData;
}
}
然后实现对应的逻辑
/**
* @author 青石路
*/
@RestController
@RequestMapping("/task")
public class SyncTaskController {
private static final Logger LOG = LoggerFactory.getLogger(SyncTaskController.class);
@PostMapping("/delete")
public ResultEntity<String> delete(@RequestBody SyncTaskDTO syncTask) {
// TODO 删除处理
LOG.info("删除任务[taskId={}]", syncTask.getTaskId());
if (syncTask.getClearData()) {
LOG.info("清空任务[taskId={}]历史数据", syncTask.getTaskId());
// TODO 清空历史数据
}
return ResultEntity.success("删除成功");
}
}
调整完之后,同事通知我,让我做对 qsl-workflow 做对应的调整。调整很简单,qsl-workflow 删除时直接传 true 即可
/**
* @author 青石路
*/
@RestController
@RequestMapping("/definition")
public class WorkflowController {
private static final Logger LOG = LoggerFactory.getLogger(WorkflowController.class);
@Resource
private OfflineSyncApi offlineSyncApi;
@PostMapping("/delete")
public ResultEntity<String> delete(@RequestBody WorkflowDTO workflow) {
LOG.info("删除工作流[workflowId={}]", workflow.getWorkflowId());
// 1.查询工作流节点,查到离线同步节点(taskId = 1)
// 2.删除工作流节点,删除离线同步节点
// 删除离线同步任务,isClearData直接传true
ResultEntity<String> syncDeleteResult = offlineSyncApi.deleteTask(new SyncTaskDTO(1L, true));
if (syncDeleteResult.getCode() != 200) {
LOG.error("删除离线同步任务[taskId={}]失败:{}", 1, syncDeleteResult.getMessage());
ResultEntity.fail(syncDeleteResult.getMessage());
}
return ResultEntity.success("删除成功");
}
}
调整完成之后,发起 http 请求,发现历史数据没有被清除,看日志发现
LOG.info("清空任务[taskId={}]历史数据", syncTask.getTaskId());
没有打印,参数明明传的是 true 吖!!!
offlineSyncApi.deleteTask(new SyncTaskDTO(1L, true));
这是哪里出了问题?

问题排查
因为 qsl-offline-sync-api 是直接引入的,并非我实现的,所以我第一时间找到了其实现者,反馈了问题后让其自测下;一开始他还很自信,说这么简单怎么会有问题

当他启动 qsl-offline-sync-server 后,发起 http 请求
POST http://localhost:8080/data-govern/sync/task/delete
Content-Type: application/json{
"taskId": 123,
"isClearData": true
}
发现 isClearData 的值是 false

此刻,疑问从我的额头转移到了他的额头上,他蒙蔽了,我轻松了。为了功能能够正常交付,我还是决定看下这个问题,没有了心理压力,也许更容易发现问题所在。第一眼看到 isClearData,我就隐约觉得有问题,所以我决定仔细看下 SyncTaskDTO 这个类,发现 isClearData 的 setter 和 getter 方法有点不一样
private Boolean isClearData = false;
public Boolean getClearData() {
return isClearData;
}
public void setClearData(Boolean clearData) {
isClearData = clearData;
}
方法名是不是少了 Is?带着这个疑问我找到了同事,问他 setter 、getter 为什么要这么命名?他说是 idea 工具自动生成的(也就是我们平时用到的idea自动生成setter、getter方法的功能)

我让他把 Is 补上试试
private Boolean isClearData = false;
public Boolean getIsClearData() {
return isClearData;
}
public void setIsClearData(Boolean isClearData) {
this.isClearData = isClearData;
}
发现传值正常了,他回过头看着我,我看着他,两人同时提问
他:为什么加了
Is就可以了?我:布尔类型的变量,你为什么要加
is前缀?
问题延申
作为一个严谨的开发,不只是要知其然,更要知其所以然;关于
为什么加了
Is就可以了
这个问题,我们肯定是要会上一会的;会这个问题之前,我们先来捋一下参数的流转,因为是基于 Spring MVC 实现的 Web 应用,所以我们可以这么问 deepseek
Spring MVC 是如何将前端参数转换成POJO的
能够查到如下重点信息

RequestResponseBodyMethodProcessor 的 resolveArgument
/**
* Throws MethodArgumentNotValidException if validation fails.
* @throws HttpMessageNotReadableException if {@link RequestBody#required()}
* is {@code true} and there is no body content or if there is no suitable
* converter to read the content with.
*/
@Override
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
parameter = parameter.nestedIfOptional();
Object arg = readWithMessageConverters(webRequest, parameter, parameter.getNestedGenericParameterType());
String name = Conventions.getVariableNameForParameter(parameter);
if (binderFactory != null) {
WebDataBinder binder = binderFactory.createBinder(webRequest, arg, name);
if (arg != null) {
validateIfApplicable(binder, parameter);
if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
throw new MethodArgumentNotValidException(parameter, binder.getBindingResult());
}
}
if (mavContainer != null) {
mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult());
}
}
return adaptArgumentIfNecessary(arg, parameter);
}
正是解析参数的地方,我们打个断点,再发起一次 http 请求

很明显,readWithMessageConverters 是处理并转换参数的地方,继续跟进去会来到 MappingJackson2HttpMessageConverter 的 readJavaType 方法

此刻我们可以得到,是通过 jackson 完成数据绑定与数据转换的。继续跟进,会看到 isClearData 的赋值过程

通过前端传过来的参数 isClearData 找对应的 setter方法是 setIsClearData,而非 setClearData,所以问题
为什么加了
Is就可以了
是不是就清楚了?
问题解决
按上述方式调整
isClearData的setter、getter方法带上
ispublic Boolean getIsClearData() {
return isClearData;
} public void setIsClearData(Boolean isClearData) {
this.isClearData = isClearData;
}
布尔类型的变量,不用
is前缀可以用
if前缀private Boolean ifClearData = false; public Boolean getIfClearData() {
return ifClearData;
} public void setIfClearData(Boolean ifClearData) {
this.ifClearData = ifClearData;
}
可以结合
@JsonProperty来处理@JsonProperty("isClearData")
private Boolean isClearData = false;
总结
Spring MVC对参数的绑定与转换,内容不同,采用的处理器也不同form表单数据(application/x-www-form-urlencoded)
处理器:
ServletModelAttributeMethodProcessorJSON 数据 (application/json)
处理器:
RequestResponseBodyMethodProcessor
转换器:MappingJackson2HttpMessageConverter多部分文件 (multipart/form-data)
处理器:
MultipartResolver
POJO的布尔类型变量,不要加is前缀命名不符合规范,集成第三方框架的时候就很容易出不好排查的问题
成不了规范的制定者,那就老老实实遵循规范!
都说了布尔类型的变量不要加 is 前缀,非要加,这不是坑我了嘛的更多相关文章
- POJO类中的任何布尔类型的变量,都不要加is
POJO类中的任何布尔类型的变量,都不要加is,否则部分框架解析会引起序列化错误. 定义为基本数据类型boolean isSuccess:的属性,它的方法也是isSuccess(),HSF框架在反向解 ...
- C++中对一个布尔类型的变量按位取反结果不变
C++中对一个bool类型的变量按位取反是无效的.例如: bool a = true; bool b = ~a; // b的值还是true
- 016 01 Android 零基础入门 01 Java基础语法 02 Java常量与变量 10 布尔类型和字符串的字面值
016 01 Android 零基础入门 01 Java基础语法 02 Java常量与变量 10 布尔类型和字符串的字面值 本文知识点:字面值 关于字面值的概念,需要注意:很多地方,我们可能就把字面值 ...
- Python 学习 第一篇:数据类型(数字,集合,布尔类型,操作符)
Python语言最常用的对象是变量和常量,常量的值是字面意思,其值是不可变的,变量的值是可变的,例如,123,"上海"是常量,而a=1,a=2,其中a是变量名.内置的核心数据类型有 ...
- POJO类中布尔类型为啥不让用isXxx命名
源码面前,了无秘密 <阿里开发规范泰山版>(2020.04.22)-->编程规约-->(一) 命名风格-->第8条规定: [强制]POJO 类中的任何布尔类型的变量,都不 ...
- BOOL布尔类型
1.BOOL数据类型,是一种表示非真即假的数据类型,布尔类型的变量只有YES和NO两个值.YES表⽰示表达式结果为真,NO表示表达式结果为假. 2.在C语言中,认为非0即为真. 3.分⽀支语句中,经常 ...
- python元组类型的变量以及字符串类型的变量作为参数进行传值
今天做selenium元素对象剥离时(我把元素对象都放到了元组类型的变量中,格式:user = (“id”,“X-Auto-2”)),遇到一个元组变量,以及str字符串变量一起作为参数传值的问题,发现 ...
- Python:Base1(数据类型,print语句,变量,定义字符串,raw字符串与多行字符串,Unicode字符串,整数和浮点数运算,布尔类型运算)
1.Python中数据类型: 计算机顾名思义就是可以做数学计算的机器,因此,计算机程序理所当然地可以处理各种数值.但是,计算机能处理的远不止数值,还可以处理文本.图形.音频.视频.网页等各种各样的数据 ...
- ECMAScript1.1 js书写位置 | 声明变量 | 基本数据类型 | 数据类型转换 | 操作符 | 布尔类型的隐式转换
js书写位置 由于在写css样式时使用的时双引号,所以我们在写js代码时建议使用单引号(‘’)! 行内式 <input type="button" value="点 ...
- Python 为什么要在 18 年前引入布尔类型?且与 C、C++ 和 Java 都不同?
花下猫语:在上一篇<Python 为什么能支持任意的真值判断? >文章中,我们分析了 Python 在真值判断时的底层实现,可以看出 Python 在对待布尔值时,采用了比较宽泛的态度.官 ...
随机推荐
- map标签是什么
<map>标签用于在HTML中定义一个 图像映射(image map),它允许你将图像划分为多个可点击的区域(称为"热点"),每个区域可以链接到不同的URL或执行不同的 ...
- AspNetCore MVC 跨域
通过XMLHttpRequest或者ajax去请求一个AspNetCore API接口服务时,Firefox提示我 已拦截跨源请求:同源策略禁止读取位于 http://localhost:33694/ ...
- .NET多线程编程之CountdownEvent使用
简单来说,使用这个类可以让主线程等待子线程都完成任务之后才执行任务 1 static void Main(string[] args) 2 { 3 ///子任务的数量 4 CountdownEvent ...
- PandasAI:当数据分析遇上自然语言处理
数据科学的新范式 在数据爆炸的时代,传统的数据分析工具正面临着前所未有的挑战.数据科学家们常常需要花费70%的时间在数据清洗和探索上,而真正的价值创造时间却被大幅压缩.PandasAI的出现,正在改变 ...
- 理解PostgreSQL和SQL Server中的文本数据类型
理解PostgreSQL和SQL Server中的文本数据类型 在使用PostgreSQL时,理解其文本数据类型至关重要,尤其对有SQL Server背景的用户而言.尽管两个数据库系统都支持文本存储, ...
- ESP32系列,IDF官方实例——外设:通用GPIO
示例位于 \examples\peripherals\gpio\generic_gpio 文件夹内 GPIO示例逻辑简单,直接看代码理解. /* GPIO示例 此示例代码位于公共域(或CC0许可,由您 ...
- 使用Python解析求解拉普拉斯方程
引言 大家好!今天我们将探讨一个经典的偏微分方程-拉普拉斯方程,并使用 Python 进行求解.拉普拉斯方程广泛应用于物理学中,尤其是在电磁学.流体力学和热传导等领域.通过这篇文章,你将了解什么是拉普 ...
- 从 MySQL 获取数据,是从磁盘读取的吗?(buffer pool)
从 MySQL 获取数据,是从磁盘读取的吗?(Buffer Pool) 在 MySQL 中,数据是否从磁盘读取取决于数据是否已经被加载到内存中.MySQL 使用 InnoDB 存储引擎 中的 Buff ...
- cglib 代理类 自己equals自己 返回false
简单的cglib代理示例 普通的 Java 类 package cglib; public class UserService { public void saveUser(String userna ...
- GeoIP库商业版调研-支持IPV6
背景 因需要支持ipv6网络,目前所使用的GeoIP库无法解析或者很少量的能解析出IPV6的IP地址位置信息,所以需要更新最新的GeoIP库文件.目的配置在Nginx或者服务直接调用使用,从而获取城市 ...