淺談Java中是否直接可以使用enum進行傳輸
背景
我們在進行傳輸的時候 會有一些狀態值,如Status為1代表刪除,為0代表失敗或者怎麼樣的。只傳輸一個)0或者1過去給第三方(此處不包括給前端),如果沒有契約第三方會不認識你這個是什麼意思,那我們在平時寫業務邏輯的時候使用列舉很輕易就知道了什麼狀態什麼值。所以我們在構建DTO物件的時候裡面放一個列舉來表示。
首先在阿里的規範裡是這樣說的:
【強制】二方庫裡可以定義列舉型別,引數可以使用列舉型別,但是介面返回值不允許使用列舉型別或者包含列舉型別的 POJO 物件。
那到底為啥不能用呢?
列舉
首先我們得先思考一下列舉是否可以進行序列化,我們在把物件進行傳輸的時候需要將這個物件序列化為位元組序列進行傳輸(在linux中一切皆檔案,JVM虛擬機器將物件變為位元組給到核心通過傳輸協議進行打包傳)列舉在進行編譯後會生成一個相關的類,這個類,這個類繼承了JavaAPI中的java.lang.Enum類。那麼我們看看這個類,毫無疑問可以序列化。繼承了Serializable介面。那麼就肯定就是可以序列化了。
Enum實戰序列化
1. 建立一個列舉類
package SerializableEnum; /** * @Author:yuanxindong * @Date:2020/5/101:33 */ public enum PersonEnum { /** * 小圓 */ YUANXINDONG("yuanxindong",1); ; private String age; private int i; PersonEnum(String yuanxindong,int i) { this.age = yuanxindong; this.i = i; }}
2.將列舉類放入Person物件,通過本地序列化存入target資料夾中,再進行反序列化,讀取檢視列舉的值
package SerializableEnum; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; /** * @Author:yuanxindong * @Date:2020/5/101:31 */ public class Person implements Serializable { private String name; PersonEnum a; public void setName(String name) { this.name = name; } public void setA(PersonEnum a) { this.a = a; } public String getName() { return name; } public PersonEnum getA() { return a; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ",a=" + a + '}'; } public static void main(String[] args) throws IOException,ClassNotFoundException { ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("object.txt")); Person p = new Person(); p.setA(PersonEnum.YUANXINDONG); p.setName("小圓"); oos.writeObject(p); ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:\\workCode\\票稅助手\\aresV3\\springCodestudy\\object.txt")); Person brady = (Person) ois.readObject(); brady.getA(); System.out.println(brady); } }
執行結果:
但是在控制檯輸出的物件是列舉的命名,沒有列舉中的值,這時為什麼呢?
==
我用的是aliFastJson轉還為JsonObject的我們看看他裡面的實現。只是拿了對應列舉的name(感覺是個坑啊),這也阿里規範中不能使用列舉放在DTO的原因之一吧==
上面的內容整明瞭列舉是可以進行序列化的,是可以被傳輸的,他的實現也是通過類來實現的,除了fastJSON那一步,使用都沒有問題的。其他角度考慮
借鑑知乎
使用列舉的確會帶來擴充套件相容性的問題,這點很多答主都說的很好了,我就說一下為什麼引數上可以使用列舉的原因吧。咱們先假定對列舉的擴充套件只是新增值,而不是減少值。比如說性別中本來是男和女,現在要增加一個transgender,但我們極少極少會有需求說,把性別中的已有男或者女去掉。(我覺得這個假設是引數可以使用列舉型的前提)在這個假定下如果我們在介面中使用列舉型,如孤盡兄在java開發手冊中所述,分為引數和返回值兩種情況。不管是微服務之間的互相呼叫,還是手機客戶端到伺服器的呼叫,在不停機的情況下,伺服器端和客戶端是很難一起更新的,往往我們是伺服器端先來支援新feature,然後再來逐步更新客戶端。我想孤盡兄說引數可以使用列舉型,也是基於這種更新升級方式。因為伺服器端如果突然開始返回transgender這個新性別,客戶端吃不進去(反序列化不了),客戶端就炸了。但如果伺服器端只是在引數上開始接受新性別,那就不怕老客戶端,反正老客戶端還在那裡繼續傳送男和女這兩種性別,伺服器端都認識,就不會出錯。兩邊可以一直相安無事,慢慢等所有客戶端都升級。但是呢,如果我們用string來代替列舉,伺服器端貿然返回一個新的值,客戶端不知道怎麼處理,也可能會產生其他問題,比如說錢算錯了之類業務層面的問題。所以客戶端程式碼可能要先更新一點,讓其能處理這個新的值。我覺得阿里把這個標準放在手冊裡,也是多年的經驗教訓,兩害相權取其輕吧。因為很多應用是沒法強制客戶端一起更新的。尤其是手機移動客戶端,ios可能還要稽核,很難做到客戶端和伺服器端同步更新。如果是微服務,也很難在不停機的情況下,把通過列舉耦合兩個微服務一起更新。
看完大佬的說法個人感覺:
是的你在一個專案中維護是沒有什麼問題。但是多個專案使用同一個列舉怎麼搞。要麼這個列舉一處動即全動。所有的專案使用這一個列舉。比如說全公司有一個通用的發票型別列舉,有幾個狀態值代表一鍾發票型別,於是這個列舉維護到公共配置上,通過動態載入技術,在每次釋出或者有修改的時候進行動態載入。感覺同完美。小白的YY。落地難嗎??試一試。後面更新。
到此這篇關於淺談Java中是否直接可以使用enum進行傳輸的文章就介紹到這了,更多相關Java enum 傳輸內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!