Java开发手册中为什么禁止使用isSuccess作为布尔类型变量名以及POJO中基本类型与包装类型的使用标准

news/2024/11/22 20:41:17/

场景

Java开发手册中关于POJO的布尔类型的变量名的要求是:

【强制】POJO 类中的任何布尔类型的变量,都不要加 is 前缀,否则部分框架解析会引起序列化错误。

说明:在本文 MySQL 规约中的建表约定第一条,表达是与否的变量采用 is_xxx 的命名方式,所以,需要

在<resultMap>设置从 is_xxx 到 xxx 的映射关系。

反例:定义为基本数据类型 Boolean isDeleted 的属性,它的方法也是 isDeleted(),框架在反向解析的时候,

“误以为”对应的属性名称是 deleted,导致属性获取不到,进而抛出异常。

 

下面来验证下上面的结论。

在日常开发中,我们会经常要在类中定义布尔类型的变量,比如在给外部系统提供一个 RPC 接口的时候,

我们一般会定义一个字段表示本次请求是否成功的。

注:

博客:
霸道流氓气质的博客_CSDN博客-C#,架构之路,SpringBoot领域博主

我们先新建以下四个POJO

Model1 :

public class Model1 {private Boolean isSuccess;public Boolean getSuccess() {return isSuccess;}public void setSuccess(Boolean success) {isSuccess = success;}
}

Model2 :

public class Model2 {private Boolean success;public Boolean getSuccess() {return success;}public void setSuccess(Boolean success) {this.success = success;}
}

Model3:

public class Model3 {private boolean isSuccess;public boolean isSuccess() {return isSuccess;}public void setSuccess(boolean success) {isSuccess = success;}
}

Model4 :

public class Model4 {private boolean success;public boolean isSuccess() {return success;}public void setSuccess(boolean success) {this.success = success;}
}

以上四个POJO都是通过IDEA自动生成的get和set方法,可以看到:

基本类型自动生成的 getter 和 setter 方法,名称都是isXXX()和setXXX()形式的。

包装类型自动生成的getter和setter方法,名称都是getXXX()和setXXX()形式的

JavaBean 中关于 setter/getter 的规范

关于 Java Bean 中的 getter/setter 方法的定义其实是有明确的规定的,根据JavaBeans(TM) Specification规定:

JavaBeans(TM) Specification 1.01 Final Release

如果是普通的参数 propertyName,要以以下方式定义其 setter/getter:
        public <PropertyType> get<PropertyName>();
        public void set<PropertyName>(<PropertyType> a);

但是,布尔类型的变量 propertyName 则是单独定义的:
        public boolean is<PropertyName>();
        public void set<PropertyName>(boolean m);

 

通过对照这份 JavaBeans 规范,我们发现,在 Model4 中,变量名为 isSuccess,如果严格按照规范定义的话,

其getter 方法应该叫 isIsSuccess。但是很多IDE 都会默认生成为 isSuccess。

Java中fastJson、jackson、Gson对于POJO的布尔变量isSuccess序列化的影响

拿常用的序列化进行举例,如果需要引入依赖,根据自己项目情况自行引入

        <dependency><groupId>com.google.code.gson</groupId><artifactId>gson</artifactId><version>2.8.9</version></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-core</artifactId><version>2.12.0</version></dependency>

引入依赖之后,示例代码如下:

        Model3 model3 = new Model3();model3.setSuccess(true);System.out.println("Serialiazable Result with fashjson:"+com.alibaba.fastjson.JSON.toJSONString(model3));com.google.gson.Gson gson = new Gson();System.out.println("Serialiazable Result with Gson:"+gson.toJson(model3));com.fasterxml.jackson.databind.ObjectMapper om = new ObjectMapper();System.out.println("Serialiazable Result with jackson:"+om.writeValueAsString(model3));

以上代码的输出结果为

        //Serialiazable Result with fashjson:{"success":true}//Serialiazable Result with Gson:{"isSuccess":true}//Serialiazable Result with jackson:{"success":true}

可以看到

在 fastjson 和 jackson 的结果中,原来类中的 isSuccess 字段被序列化成success。

而 Gson 中是 isSuccess 字段。

fastjson 和 jackson 在把对象序列化成 json 字符串的时候,是通过反射遍历出该类中的所有 getter 方法,

得到isSuccess,然后根据 JavaBeans 规则,他会认为这是属性success的值。直接序列化成 json:{"success":true}

但是 Gson 并不是这么做的,他是通过反射遍历该类中的所有属性,并把其值序列化成 json:{“isSuccess”:true}

可以看到,由于不同的序列化工具,在进行序列化的时候使用到的策略是不一样的,

所以,对于同一个类的同一个对象的序列化结果可能是不同的。

如果对于同一个对象,使用fastjson进行序列化,再使用Gson反序列化会发生什么?

测试代码如下:

 System.out.println(gson.fromJson(com.alibaba.fastjson.JSON.toJSONString(model3),Model3.class).isSuccess());

以上输出结果为false

原因是因为 JSON 框架通过扫描所有的 getter后发现有一个isSuccess方法,然后根据JavaBeans的规范,解析出变量名为success,

把 model 对象序列化城字符串后内容为{"success":true}。根据{"success":true}这个 json 串,

Gson 框架在通过解析后,通过反射寻找 Model 类中的 success 属性,

 但是 Model 类中只有 isSuccess 属性,所以,最终反序列化后的 Model 类的对象中,isSuccess 则会使用默认值 false。

所以,在定义 POJO 中的布尔类型的变量时,不要使用 isSuccess 这种形式,而要直接使用 success !

Java的POJO中布尔变量使用基本数据类型boolean还是包装数据类型Boolean

新建一个POJO

import java.util.StringJoiner;public class Model {private Boolean success;private boolean failure;public Boolean getSuccess() {return success;}public void setSuccess(Boolean success) {this.success = success;}public boolean isFailure() {return failure;}public void setFailure(boolean failure) {this.failure = failure;}@Overridepublic String toString() {return new StringJoiner(",",Model.class.getSimpleName()+"[","]").add("success = "+success).add("failure= "+failure).toString();}
}

并使用Java 8的StringJoiner重写toString方法。

然后输出该对象的toString

        Model model = new Model();System.out.println("default model: "+model);

以上代码输出结果

default model: Model[success = null,failure= false]

可以看到,当我们没有设置 Model 对象的字段的值的时候,Boolean 类型的变量会设置默认值为null,

而 boolean 类型的变量会设置默认值为false。即对象的默认值是null,boolean 基本数据类型的默认值是false。

在 Java 开发手册中,对于 POJO 中如何选择变量的类型也有着一些规定

关于基本数据类型与包装数据类型的使用标准如下:

1) 【强制】所有的 POJO 类属性必须使用包装数据类型。

2) 【强制】RPC 方法的返回值和参数必须使用包装数据类型。

3) 【推荐】所有的局部变量使用基本数据类型。

说明:POJO 类属性没有初值是提醒使用者在需要使用时,必须自己显式地进行赋值,任何 NPE 问题,或者入库检查,都由使用者来保证。

正例:

数据库的查询结果可能是 null,因为自动拆箱,用基本数据类型接收有 NPE 风险。

反例:

某业务的交易报表上显示成交总额涨跌情况,即正负 x%,x 为基本数据类型,调用的 RPC 服务,调

用不成功时,返回的是默认值,页面显示为 0%,这是不合理的,应该显示成中划线-。所以包装数据类型

的 null 值,能够表示额外的信息,如:远程调用失败,异常退出。

 


http://www.ppmy.cn/news/240027.html

相关文章

Java教程【01.05】Java内部类

Java内部类 Java内部类是一种嵌套在其他类中的类。它具有访问外部类的成员的能力,并提供了一种组织和封装代码的方式。在本教程中,我们将探讨Java内部类的使用和相关概念。 步骤1:创建外部类 首先,我们需要创建一个外部类,内部类将嵌套在其中。以下是一个示例外部类的代…

【Unity XCharts - 01】XCharts图表库简介

XCharts 图表库简介 1.概述2.官方资源简介2.1 官网介绍2.2 本体源码资源2.3 Unity .unitypackage 资源包2.4 Demo代码资源 ❤️ 打不开地址、下载慢的话童鞋可以在我的资源中下载 3.6.0 版本相关的资源。❤️ → 开源Unity图表库&#xff1a;XCharts 3.6.0 ← 1.概述 XCharts …

Cesium 热力图

var points []; var width 600; var height 400; var max 100; // 热力图经纬度范围 var latMin 28.364807; var latMax 40.251095; var lonMin 94.389228; var lonMax 108.666357; // 根据热力图图片范围&#xff0c;生成随机热力点和强度值 for (var i 0; i < 30…

浅谈 ByteHouse Projection 优化实践

预聚合是 OLAP 系统中常用的一种优化手段&#xff0c;在通过在加载数据时就进行部分聚合计算&#xff0c;生成聚合后的中间表或视图&#xff0c;从而在查询时直接使用这些预先计算好的聚合结果&#xff0c;提高查询性能&#xff0c;实现这种预聚合方法大多都使用物化视图来实现…

Java教程【01.01】 对象和类

Java技术栈: 对象和类 什么是对象和类? 在Java中,对象是具有属性和行为的实体,而类是一组定义操作和属性的规范或蓝图。类包含数据成员(变量)和方法(函数),对象是类的实例化。 如何创建一个对象? 要创建一个对象,必须先定义一个类。下面是一个简单的Java类和对象…

proxmox7.4 安装后配置

关于proxmox7安装和配置的博文&#xff0c;倒是不少。可惜鱼龙混杂&#xff0c;踩了不少坑&#xff0c;如今实践成功后&#xff0c;做一分享。 proxmox7.4安装(与安装linux系统类似) 1.去官网https://proxmox.com/en/downloads 下载安装镜像&#xff0c;注意&#xff1a; 下…

自学编程的艰辛和乐趣

随着信息技术的快速发展&#xff0c;编程已经成为一个越来越重要的技能。那么&#xff0c;我们该如何入门编程呢&#xff1f;本文将分享自学编程需要注意的事项、编程初学者学习语言的建议、好的习惯、学习方法以及提高编程能力和资料分享。 一、自学编程需要注意什么&#xf…

手机模拟器安装Xposed框架

如何在手机模拟器上安装xposed呢&#xff1f; 工具准备&#xff1a; 1.手机模拟器&#xff08;以雷电模拟器为例子&#xff09; 2.FQ软件 3.xposedinstaller 安装过程&#xff1a; 1.下载一个豌豆荚&#xff08;别的应用市场也可以&#xff09; 2.搜索xposed框架 3.安装…