在閱讀《阿里巴巴Java開發(fā)手冊》時(shí),發(fā)現(xiàn)有一條關(guān)于二方庫依賴中接口返回值不允許使用枚舉類型的規(guī)約脚作,具體內(nèi)容如下:
在談?wù)摓槭裁粗跋葋砜破障率裁词嵌綆欤?strong>二方庫也稱作二方包葫哗,一般指公司內(nèi)部發(fā)布到中央倉庫,可供公司內(nèi)部其他應(yīng)用依賴的庫(jar 包)球涛。
那么一方庫便是本工程內(nèi)部子項(xiàng)目模塊依賴的庫劣针;三方庫為公司之外的開源庫,比如像 fastjson亿扁、easyexcel
這種捺典。
下面我們就通過一個(gè)例子來看下為什么阿里巴巴不允許返回枚舉類型或者包含枚舉類型的 POJO 對(duì)象。
比如星巴克提供了 0.0.1
版本的二方庫从祝,定義了一個(gè) Starbucks
類襟己,里面包含了枚舉類型的 SizeEnum
,里面分別是中杯牍陌、大杯擎浴、特大杯。
public class Starbucks implements Serializable {
private Long id;
private String name;
private Integer capacity;
private SizeEnum sizeEum;
}
public enum SizeEnum {
TALL(1),
GRANDE(2),
VENTI(3)
}
定義了一個(gè)服務(wù)類毒涧,實(shí)現(xiàn)了根據(jù) id
獲取星巴克的方法:
public class StarbucksImpl implements StarbucksService {
public Starbucks getStarbucksById(Long id) {
Starbucks starbucks = new Starbucks();
starbucks.setId(1L);
starbucks.setName("Latte");
starbucks.setCapacity(360);
starbucks.setSizeEnum(SizeEnum.TALL);
return starbucks;
}
}
然后贮预,星巴克的門店引入 0.0.1
這個(gè)版本 jar 包,然后賣的好好的:
public class StarbucksDemo {
@Resource
private StarbucksService starbucksService;
public void getStarbucks() {
Starbucks starbucks = starbucksService.getStarbucksById(1L);
System.out.println(starbucks);
}
}
有一天契讲,老羅說要那個(gè)中等大小的中杯拿鐵仿吞,但是服務(wù)員說那是大杯,經(jīng)過一番爭論怀泊,羅老師很是生氣茫藏。
于是星巴克升級(jí)到了 0.0.2
版本二方庫,在枚舉類 SizeEnum
中新增了小杯霹琼,升級(jí)后的枚舉類如下:
public enum SizeEnum {
TALL(1),
GRANDE(2),
VENTI(3),
SHORT(4)
}
同時(shí)服務(wù)類的接口方法也做了相應(yīng)修改:
public class StarbucksImpl implements StarbucksService {
public Starbucks getStarbucksById(Long id) {
Starbucks starbucks = new Starbucks();
starbucks.setId(1L);
starbucks.setName("Latte");
starbucks.setCapacity(240);
starbucks.setSizeEnum(SizeEnum.SHORT);
return starbucks;
}
}
由于星巴克的門店比較多务傲,有的還不知道這個(gè)新加的需求凉当,因此返回結(jié)果中出現(xiàn)了 SHORT
,但是 0.0.1
版本的二方庫中沒有小杯啊售葡,所以就出問題了看杭,也就是序列化失敗。
通過這個(gè)例子挟伙,我相信大家對(duì)枚舉類型作為返回結(jié)果有了一定的理解楼雹,下面引用孤盡大佬在知乎的回答:
由于升級(jí)原因,導(dǎo)致雙方的枚舉類不盡相同尖阔,在接口解析贮缅,類反序列化時(shí)出現(xiàn)異常。
Java 中出現(xiàn)的任何元素介却,在 Gosling 的角度都會(huì)有背后的思考和邏輯(盡管并非絕對(duì)完美谴供,但 Java 的頂層抽象已經(jīng)是天才級(jí)了),比如:接口齿坷、抽象類桂肌、注解、和本文提到的枚舉永淌。枚舉有好處崎场,類型安全,清晰直接遂蛀,還可以使用等號(hào)來判斷谭跨,也可以用在 switch 中。它的劣勢也是明顯的李滴,就是不要擴(kuò)展饺蚊。可是為什么在返回值和參數(shù)進(jìn)行了區(qū)分呢悬嗓,如果不兼容,那么兩個(gè)都有問題裕坊,怎么允許參數(shù)可以有枚舉包竹。當(dāng)時(shí)的考慮,如果參數(shù)也不能用籍凝,那么枚舉幾乎無用武之地了周瞎。參數(shù)輸出,畢竟是本地決定的饵蒂,你本地有的声诸,傳送過去,向前兼容是不會(huì)有問題的退盯。但如果是接口返回彼乌,就比較惡心了泻肯,因?yàn)榻馕龌貋淼倪@個(gè)枚舉值,可能本地還沒有慰照,這時(shí)就會(huì)拋出序列化異常灶挟。
比如:你的本地枚舉類,有一個(gè)天氣 Enum:SUNNY, RAINY, CLOUDY毒租,如果根據(jù)天氣計(jì)算心情的方法:guess(WeatcherEnum xx)稚铣,傳入這三個(gè)值都是可以的。返回值:Weather guess(參數(shù))墅垮,那么對(duì)方運(yùn)算后惕医,返回一個(gè) SNOWY,本地枚舉里沒有這個(gè)值算色,傻眼了抬伺。
總結(jié)
本文通過一個(gè)實(shí)例讓大家理解到枚舉類型作為返回結(jié)果的坑,大家可以使用基本類型或者基本類型包裝類來替換掉枚舉類型就可以避免掉這么問題了剃允。
大家對(duì)于這條規(guī)約?有什么看法沛简,也歡迎留言討論。?
最好的關(guān)系就是互相成就斥废,大家的在看椒楣、轉(zhuǎn)發(fā)、留言三連就是我創(chuàng)作的最大動(dòng)力牡肉。
參考
《Java開發(fā)手冊》泰山版