程序員新人上午使用 isXxx 形式定義布爾類型,下午就被勸退?
小二是新來的背鍋俠,哦,不不不,新來的實(shí)習(xí)生。面試過程中表現(xiàn)得非常不錯(cuò),各種問題對答如流,老板和我都倍感欣慰。
這么優(yōu)秀的人,絕不能讓他浪費(fèi)一分一秒,于是很快,我就給他安排了一個(gè)非常簡單的任務(wù)。
大家都知道,在日常開發(fā)中,我們會經(jīng)常要在類中定義布爾類型的變量,比如在給外部系統(tǒng)提供一個(gè) RPC 接口的時(shí)候,我們一般會定義一個(gè)字段表示本次請求是否成功的。
關(guān)于這個(gè)”本次請求是否成功”的字段的定義,我見過很多不同的開發(fā)者,定義的方式都不同,尤其是在屬性的命名上,有人用 success,有人用 isSuccess 表示。
從語義上面來講,兩種命名方式都可以講的通,并且也都沒有歧義。
這不,小二就采用了 isSuccess 的形式來定義布爾類型的變量,于是下午 review 的時(shí)候就被眼尖的老板揪了出來。老板畢竟是在阿里待過的,對這些細(xì)節(jié)扣的很細(xì)。
于是大發(fā)雷霆,準(zhǔn)備當(dāng)場勸退小二,被我攔了下來。畢竟自己面試的人,不看僧面看佛面,是吧?于是老板答應(yīng)我說再試用一個(gè)月看看。
isSuccess 會有什么問題呢?小二很是不解。
那根據(jù) JavaBeans Specification 的規(guī)定,如果是普通的參數(shù) propertyName,要以以下方式定義其 setter/getter:
public <PropertyType> get<PropertyName>();
public void set<PropertyName>(<PropertyType> a);
但是,布爾類型的變量 propertyName 則是單獨(dú)定義的:
public boolean is<PropertyName>();
public void set<PropertyName>(boolean m);
success 方法的 getter 應(yīng)該是 isSuccess/getSuccess,而 isSuccess 的 getter 應(yīng)該是 isIsSuccess/getIsSuccess。
但是很多人,在使用 isSuccess 作為屬性名的時(shí)候,還是會采用 isSuccess/getSuccess 作為 getter 方法名,尤其是現(xiàn)在的很多 IDE 在默認(rèn)生成 getter 的時(shí)候也是會生成 isSuccess。
在一般情況下,其實(shí)是沒有影響的。但是有一種特殊情況就會有問題,那就是發(fā)生序列化的時(shí)候可能會導(dǎo)致參數(shù)轉(zhuǎn)換異常。
我們先來定義一個(gè) JavaBean:
class Model 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 getWanger(){
return "hollis";
}
}
在這個(gè) JavaBean 中,有一個(gè)成員變量 isSuccess,三個(gè)方法,分別是 IDE 幫我們自動生成的 isSuccess 和 setSuccess,另外一個(gè)是作者自己增加的一個(gè)符合 getter 命名規(guī)范的方法。
我們分別使用不同的 JSON 序列化工具來對這個(gè)類的對象進(jìn)行序列化和反序列化:
public class BooleanMainTest {
public static void main(String[] args) throws IOException {
//定一個(gè)Model類型
Model model = new Model();
model.setSuccess(true);
//使用fastjson(1.2.16)序列化model成字符串并輸出
System.out.println("Serializable Result With fastjson :" + JSON.toJSONString(model));
//使用Gson(2.8.5)序列化model成字符串并輸出
Gson gson =new Gson();
System.out.println("Serializable Result With Gson :" +gson.toJson(model));
//使用jackson(2.9.7)序列化model成字符串并輸出
ObjectMapper om = new ObjectMapper();
System.out.println("Serializable Result With jackson :" +om.writeValueAsString(model));
}
}
以上代碼輸出結(jié)果:
Serializable Result With fastjson :{"wanger":"hollis","success":true}
Serializable Result With Gson :{"isSuccess":true}
Serializable Result With jackson :{"success":true,"wanger":"hollis"}
在 fastjson 和 jackson 的結(jié)果中,原來類中的 isSuccess 字段被序列化成 success,并且其中還包含 wanger 值。而 Gson 中只有 isSuccess 字段。
我們可以得出結(jié)論:fastjson 和 jackson 在把對象序列化成 json 字符串的時(shí)候,是通過反射遍歷出該類中的所有 getter 方法,得到 getHollis 和 isSuccess,然后根據(jù) JavaBeans 規(guī)則,他會認(rèn)為這是兩個(gè)屬性 hollis 和 success 的值。直接序列化成 json:
{“wanger”:”沉默王二”,”success”:true}
但是 Gson 并不是這么做的,他是通過反射遍歷該類中的所有屬性,并把其值序列化成 json:
{“isSuccess”:true}
可以看到,由于不同的序列化工具,在進(jìn)行序列化的時(shí)候使用到的策略是不一樣的,所以,對于同一個(gè)類的同一個(gè)對象的序列化結(jié)果可能是不同的。那么,如果我們把一個(gè)對象使用 fastjson 進(jìn)行序列化,再使用 Gson 反序列化會發(fā)生什么呢?
public class BooleanMainTest {
public static void main(String[] args) throws IOException {
Model model = new Model();
model.setSuccess(true);
Gson gson =new Gson();
System.out.println(gson.fromJson(JSON.toJSONString(model),Model.class));
}
}
以上代碼,輸出結(jié)果:
Model[isSuccess=false]
這和我們預(yù)期的結(jié)果完全相反,原因是因?yàn)?JSON 框架通過掃描所有的 getter 后發(fā)現(xiàn)有一個(gè) isSuccess 方法,然后根據(jù) JavaBeans 的規(guī)范,解析出變量名為 success,把 model 對象序列化成字符串后內(nèi)容為{"success":true}。
根據(jù){"success":true}這個(gè) json 串,Gson 框架在通過解析后,通過反射尋找 Model 類中的 success 屬性,但是 Model 類中只有 isSuccess 屬性,所以,最終反序列化后的 Model 類的對象中,isSuccess 則會使用默認(rèn)值 false。
但是,一旦以上代碼發(fā)生在生產(chǎn)環(huán)境,這絕對是一個(gè)致命的問題。
所以,作為開發(fā)者,我們應(yīng)該想辦法盡量避免這種問題的發(fā)生。
所以,建議大家使用 success 而不是 isSuccess 這種形式。 這樣,該類里面的成員變量時(shí) success,getter 方法是 isSuccess,這是完全符合 JavaBeans 規(guī)范的。無論哪種序列化框架,執(zhí)行結(jié)果都一樣。就從源頭避免了這個(gè)問題。
沒有什么使我停留——除了目的,縱然岸旁有玫瑰、有綠蔭、有寧靜的港灣,我是不系之舟。

JDK9為何要將String的底層實(shí)現(xiàn)由char[]改成了byte[]?

竟然有一半的人不知道 for 與 foreach 的區(qū)別???

消息冪等(去重)通用解決方案,RocketMQ
關(guān)注公眾號【Java技術(shù)江湖】后回復(fù)“PDF”即可領(lǐng)取200+頁的《Java工程師面試指南》
強(qiáng)烈推薦,幾乎涵蓋所有Java工程師必知必會的知識點(diǎn),不管是復(fù)習(xí)還是面試,都很實(shí)用。

