加入收藏 | 设为首页 |

ope体育电竞官网-为什么激烈制止开发人员运用isSuccess作为变量名

海外新闻 时间: 浏览:212 次

在日常开发中,咱们会常常要在类中界说布尔类型的变量,比方在给外部体系供给一个RPC接口的时分,咱们一般会界说一个字段表明本次恳求是否成功的。

关于这个"本次恳求是否成功"的字段的界说,其实是有许多种考究和坑的,稍有不小心就会掉入坑里,作者在好久之前就遇到过相似的问题,本文就来环绕这个简略剖析一下。究竟该怎么定一个布尔类型的成员变量。

一般情况下,咱们能够有以下四种办法来界说一个布尔类型的成员变量:

boolean success
boolean isSuccess
Boolean success
Boolean isSuccess

以上四种界说办法,你日常开发中最常用的是哪种呢?究竟哪一种才是正确的运用姿态呢?

经过调查咱们能够发现,前两种和后两种的首要差异是变量的类型不同,前者运用的是boolean,后者运用的是Boolean。

别的,第一种和第三种在界说变量的时分,变量命名是success,而别的两种运用isSuccess来命名的。

首要,咱们来剖析一下,究竟应该是用success来命名,仍是运用isSuccess更好一点。

success 仍是 isSuccess

究竟应该是用success仍是isSuccess来给变量命名呢?从语义上面来讲,两种命名办法都能够讲的通,而且也都没有歧义。那么还有什么准则能够参阅来让咱们做挑选呢。

在阿里巴巴Java开发手册中关于这一点,有过一个『强制性』规矩:

那么,为什么会有这样的规矩呢?咱们看一下POJO中布尔类型变量不同的命名有什么差异吧。

class Model1 {
private Boolean isSuccess;
public void setSuccess(Boolean success) {
isSuccess = success;
}
public Boolean getSuccess() {
return isSuccess;
}
}
class Model2 {
private Boolean success;
public Boolean getSuccess() {
return success;
}
public void setSuccess(Boolean success) {
this.success = success;
}
}
class Model3 {
private boolean isSuccess;
public boolean isSuccess() {
return isSuccess;
}
public void setSuccess(boolean success) {
isSuccess = success;
}
}
class Model4 {
private boolean success;
public boolean isSuccess() {
return success;
}
public void setSuccess(boolean success) {
this.success = success;
}
}

以上代码的setter/getter是运用Intellij IDEA主动生成的,仔细调查以上代码,你会发现以下规矩:

  • 根本类型主动生成的getter和setter办法,称号都是isXXX()和setXXX()办法的。
  • 包装类型主动生成的getter和setter办法,称号都是getXXX()和setXXX()办法的。

已然,咱们ope体育电竞官网-为什么激烈制止开发人员运用isSuccess作为变量名现已达到共同一致运用根本类型boolean来界说成员变量了,那么咱们再来详细看下Model3和Model4中的setter/getter有何差异。

咱们能够发现,尽管Model3和Model4中的成员变量的称号不同,一个是success,别的一个是isSuccess,可是他们主动生成的getter和setter办法称号都是isSuccess和setSuccess。

Java Bean中关于setter/getter的标准

关于Java Bean中的getter/setter办法的界说其实是有清晰的规矩的,依据JavaBeans(TM) Specification规矩,假如是一般的参数propertyName,要以以下办法界说其setter/getter:

public  get();
public void set( a);

可是,布尔类型的变量propertyName则是独自界说的:

public boolean is();
public void set(boolean m);

经过对照这份JavaBeans标准,咱们发现,在Model4中,变量名为isSuccess,假如严厉依照标准界说的话,他的getter办法应该叫isIsSuccess。可是许多IDE都会默许生成为isSuccess。

那这样做会带来什么问题呢。

在一般情况下,其实是没有影响的。可是有一种特别情况就会有问题,那便是发作序列化的时分。

序列化带来的影响

关于序列化和反序列化请参阅Java目标的序列化与反序列化。咱们这儿拿比较常用的JSON序列化来举例,看看看常用的fastJson、jackson和Gson之间有何差异:

public class BooleanMainTest {
public static void main(String[] args) throws IOException {
//定一个Model3类型
Model3 model3 = new Model3();
model3.setSuccess(true);
//运用fastjson(1.2.16)序列化model3成字符串并输出
System.out.println("Serializable Result With fastjson :" + JSON.toJSONString(model3));
//运用Gson(2.8.5)序列化model3成字符串并输出
Gson gson =new Gson();
System.out.println("Serializable Result With Gson :" +gson.toJson(model3));
//运用jackson(2.9.7)序列化model3成字符串并输出
ObjectMapper om = new ObjectMapper();
System.out.println("Serializable Result With jackson :" +om.writeValueAsString(model3));
}
}
class Model3 implements Serializable {
private static final long serialVersionUID = 1836697963736227954L;
private boolean isSuccess;
public boolean isSuccess() {
return isSuccess;
}
public void setSuccess(boolean success) {
isSuccess = success;
}
public String getHollis(){
return "hollischuang";
}
}

以上代码的Model3中,只要一个成员变量即isSuccess,三个办法,分别是IDE帮咱们主动生成的isSuccess和setSuccess,别的一个是作者自己添加的一个契合getter命名标准的办法。

以上代码输出成果:

Serializable Result With fastjson :{"hollis":"hollischuang","success":true}
Serializable Result With Gson :{"isSuccess":true}
Serializable Result With jackson :{"success":true,"hollis":"hollischuang"}

在fastjson和jackson的成果中,本来类中的isSuccess字段被序列化成success,而且其间还包括hollis值。而Gson中只要isSuccess字段。

咱们能够得出结论:fastjson和jackson在把目标序列化成json字符串的时分,是经过反射遍历出该类中的一切getter办法,得到getHollis和isSuccess,然后依据JavaBeans规矩,他会以为这是两个特点hollis和success的值。直接序列化成json:{"hollis":"hollischuang","success":true}

可是Gson并不是这么做的,他是经过反射遍历该类中的一切特点,并把其值序列化成json:{"isSuccess":true}

能够看到,因为不同的序列化东西,在进行序列化的时分运用到的战略是不相同的,所以,关于同一个类的同一个目标的序列化成果或许是不同的。

前面说到的关于对getHollis的序列化只是为了阐明fastjson、jackson和Gson之间的序列化战略的不同,咱们暂时把他放到一边,咱们把他从Model3中删去后,从头履行下以上代码,得到成果:

Serializable Result With fastjson :{"success":true}
Serializable Result With Gson :{"isSuccess":true}
Serializable Result With jackson :{"success":true}

现在,不同的序列化结构得到的json内容并不相同,假如关于同一个目标,我运用fastjson进行序列化,再运用Gson反序列化会发作什么?

public class BooleanMainTest {
public static void main(String[] args) throws IOException {
Model3 model3 = new Model3();
model3.setSuccess(true);
Gson gson =new Gson();
Syope体育电竞官网-为什么激烈制止开发人员运用isSuccess作为变量名stem.out.println(gson.fromJson(JSON.toJSONString(model3),Model3.class));
}
}
class Model3 implements Serializable {
private static final long serialVersionUID = 1836697963736227954L;
private boolean isSuccess;
public boolean isSuccess() {
return isSuccess;
}
public void setSuccess(boolean success) {
isSuccess = success;
}
@Override
public String toString冯秀梅的疯狂() {
return new StringJoiner(", ", Model3.class.getSimpleName() + "[", "]")
.add("isSuccess=" + isSuccess)
.toString();
}
}

以上代码,输出成果:

Model3[isSuccess=false]

这和咱们预期的成果彻底相反,原因是因为JSON结构经过扫描一切的getter后发现有一个isSuccess办法,然后依据JavaBeans的标准,解分出变量名为success,把model目标序列化城字符串后内容为{"success":true}。

依据{"success":true}这个json串,Gson结构在经过解析后,经过反射寻觅Model类中的success特点,可是Model类中只要isSuccess特点,所以,终究反序列化后的Model类的目标中,isSuccess则会运用默许值false。

可是,一旦以上代码发作在出产环境,这肯定是一个丧命的问题。

所以,作为开发者,咱们应该想办法尽量防止这种问题的发作,关于POJO的规划者来说,只需要做简略的一件事就能够处理这个问题了,那便是把isSuccess改为success。这样,该类里边的成员变量时success,getter办法是isSuccess,这是彻底契合JavaBeans标准的。不管哪种序列化结构,履行成果都相同。就从源头防止了这个问题。

引证以下R大关于阿里巴巴Java开发手册这条规矩的点评(https://www.zhihu.com/question/55642203):

所以,在界说POJO中的布尔类型的变量时,不要运用isSuccess这种办法,而要直接运用success!

Boolean仍是boolean?

前面咱们介绍完了在success和isSuccess之间怎么挑选,那么扫除过错答案后,备选项还剩余:

boolean success
Boolean success

那么,究竟应该是用Boolean仍是boolean来给定一个布尔类型的变量呢?

咱们知道,boolean是根本数据类型,而Boolean是包装类型。关于根本数据类型和包装类之间的联系和差异请参阅一文读懂什么是Java中的主动拆装箱

那么,在界说一个成员变量的时分究竟是运用包装类型更好ope体育电竞官网-为什么激烈制止开发人员运用isSuccess作为变量名仍是运用根本数据类型呢?

咱们来看一段简略的代码

 /**
* @auope体育电竞官网-为什么激烈制止开发人员运用isSuccess作为变量名thor Hollis
*/
public class BooleanMainTest {
public static void main(String[] args) {
Model model1 = new Model();
System.out.println("default model : " + model1);
}
}
class Model {
/**
* 定一个Boolean类型的success成员变量
*/
private Boolean success;
/**
* 定一个boolean类型的failure成员变量
*/
private boolean failure;
/**
* 掩盖toString办法,运用Java 8 的StringJoiner
*/
@Override
public String toString() {
return new StringJoiner(", ", Model.class.getSimpleName() + "[", "]")
.add("success=" + success)
.add("failure=" + failure)
.toString();
}
}

以上代码输出成果为:

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

能够看到,当咱们没有设置Model目标的字段的值的时分,Boolean类型的变量会设置默许值为null,而boolean类型的变量会设置默许值为false。

即目标的默许值是null,boolean根本数据类型的默许值是false。

在阿里巴巴Java开发手册中,关于POJO中怎么挑选变量的类型也有着一些规矩:

这儿主张咱们运用包装类型,原因是什么呢?

举一个扣费的比如,咱们做一个扣费体系,扣费时需要从外部的定价体系中读取一个费率的值,咱们预期该接口的回来值中会包括一个浮点型的费率字段。当咱们取到这个值得时分就运用公式:金额*费率=费用 进行核算,核算成果进行划扣。

假如因为计费体系反常,他或许会回来个默许值,假如这个字段是Double类型的话,该默许值为null,假如该字段是double类型的话,该默许值为0.0。

假如扣费体系关于该费率回来值没做特别处理的话,拿到null值进行核算会直接报错,阻断程序。拿到0.0或许就直接进行核算,得出接口为0后进行扣费了。这种反常情况就无法被感知。

这种运用包装类型界说变量的办法,经过反常来阻断程序,从而能够被识别到这种线上问题。假如运用根本数据类型的话,体系或许不会报错,从而以为无反常。

以上,便是主张在POJO和RPC的回来值中运用包装类型的原因。

可是关于这一点,作者之前也有过不同的观念:关于布尔类型的变量,我以为能够和其他类型区别开来,作者并不以为运用null从而导致NPE是一种最好的实践。因为布尔类型只要true/false两种值,咱们彻底能够和外部调用方约好好当回来值为false时的清晰语义。

后来,作者独自和《阿里巴巴Java开发手册》、《码出高效》的作者——孤尽 独自1V1(qing) Battle(jiao)了一下。终究达到一致,仍是尽量运用包装类型。

可是,作者仍是想着重一个我的观念,尽量防止在你的代码中呈现不确定的null值。

null何罪之有?

关于null值的运用,我在运用Optional防止NullPointerException、9 Things about Null in Java等文中就介绍过。

null是很不置可否的,许多时分会导致令人疑问的的过错,很难去判别回来一个null代表着什么意思。

图灵奖得主Tony Hoare 从前揭露表达过null是一个糟糕的规划。

我把 null 引证称为自己的十亿美元过错。它的创造是在1965 年,那时我用一个面向目标言语( ALGOL W )规划了第一个全面的引证类型体系。我的意图是保证一切引证的运用都是肯定安全的,编译器会主动进行检查。可是我未能抵挡住引诱,加入了Null引证,只是是因为完成起来十分简单。它导致了数不清的过错、缝隙和体系溃散,或许在之后 40 年中造成了十亿美元的丢失。

当咱们在规划一个接口的时分,关于接口的回来值的界说,尽量防止运用Boolean类型来界说。大多数情况下,他人运用咱们的接口回来值时或许用if(response.isSuccess){}else{}的办法,假如咱们因为疏忽没有设置success字段的值,就或许导致NPE(java.lang.NullPointerException),这显着是咱们不期望看到的。

所以,当咱们要界说一个布尔类型的成员变量时,尽量挑选boolean,而不是Boolean。当然,编程中并没有肯定。

总结

本文环绕布ope体育电竞官网-为什么激烈制止开发人员运用isSuccess作为变量名尔类型的变量界说的类型和命名展开了介绍,终究咱们能够得出结论,在界说一个布尔类型的变量,尤其是一个给外部供给的接口回来值时,要运用success来命名,阿里巴巴Java开发手册主张运用封装类来界说POJO和RPC回来值中的变量。可是这不意味着能够随意的运用null,咱们仍是要尽量防止呈现对null的处理的。

作者:Hollis