Java枚举:小小enum,优雅而干净
來源:沉默王二(ID:cmower)
《Java編程思想》中有這么一句話:“有時(shí)恰恰因?yàn)樗?#xff0c;你才能夠‘優(yōu)雅而干凈’地解決問題”——這句話說的是誰呢?就是本篇的主角——枚舉(Enum)——大家鼓掌了。
在之前很長時(shí)間一段時(shí)間里,我都不怎么用枚舉,因?yàn)榭偢杏X它沒什么用處——這其實(shí)就是“自我認(rèn)知”的短見。當(dāng)一個(gè)人一直蹲在自己的深井里而不敢跳出來的話,那他真的只能看到井口那么大點(diǎn)的天空。
隨著時(shí)間的推移,我做的項(xiàng)目越來越多,和枚舉見面的機(jī)會(huì)也越來越多,于是我就漸漸地對它越來越有興趣,研究得多了,才發(fā)現(xiàn)原來枚舉如此的優(yōu)秀。
1)枚舉的常規(guī)用法
一個(gè)精簡的枚舉非常的干凈優(yōu)雅,見下例。
public?enum?Chenmo?{WANGER,?WANGSAN,?WANGSI }我們?yōu)槌聊杜e創(chuàng)建了三個(gè)值,分別是王二、王三、王四。這段代碼實(shí)際上調(diào)用了3次Enum(String name, int ordinal)(ordinal單詞的意思為順序),也就是:
new?Enum<Chenmo>("WANGER",?0); new?Enum<Chenmo>("WANGSAN",?1); new?Enum<Chenmo>("WANGSI",?2);我們來遍歷輸出一下枚舉:
for?(Chenmo?e?:?Chenmo.values())?{System.out.println(e); } //輸出 //WANGER //WANGSAN //WANGSI2)作為switch的判斷條件
使用枚舉作為switch語句判斷條件能讓我們的代碼可讀性更強(qiáng),示例如下。
Chenmo?key?=?Chenmo.WANGER; switch?(key)?{ case?WANGSI:System.out.println("今天我送出一個(gè)CSDN大鼠標(biāo)墊");break; case?WANGSAN:System.out.println("今天我被坑一個(gè)CSDN學(xué)院年卡");break; default:System.out.println("今天我一邊高興,一邊失落");break; }在通過case關(guān)鍵字判斷的時(shí)候,可以直接使用枚舉值,非常簡潔。另外,在編譯期間限定類型,可以有效的避免越界的情況——字符串常量類型在作為switch判斷條件的時(shí)候很容易因?yàn)檎`寫而發(fā)生越界問題。
3)枚舉實(shí)現(xiàn)單例
《Effective Java》一書中對使用枚舉實(shí)現(xiàn)單例的方式推崇備至:
使用枚舉實(shí)現(xiàn)單例的方法雖然還沒有廣泛采用,但是單元素的枚舉類型已經(jīng)成為實(shí)現(xiàn)Singleton的最佳方法。
我覺得“雖然還沒有廣泛采用”幾個(gè)字可以去掉了,時(shí)至今日,大家應(yīng)該都知道:使用枚舉實(shí)現(xiàn)單例是一種非常好的方式。
先來看“雙重校驗(yàn)鎖”實(shí)現(xiàn)的單例:
public?class?SingleTon2?{//?私有化構(gòu)造方法private?SingleTon2()?{};private?static?volatile?SingleTon2?singleTon?=?null;public?static?SingleTon2?getInstance()?{//?第一次校驗(yàn)if?(singleTon?==?null)?{synchronized?(SingleTon2.class)?{//?第二次校驗(yàn)if?(singleTon?==?null)?{singleTon?=?new?SingleTon2();}}}return?singleTon;} }再來看枚舉實(shí)現(xiàn)的單例:
public?enum?SingleTon?{INSTANCE;public?void?method()?{System.out.println("我很快樂!");} }不比不知道,一比嚇一跳啊!枚舉方式的單例簡單到爆——為了不至于看起來太過精簡,我還加了一個(gè)輸出“我很快樂”的方法。
枚舉實(shí)現(xiàn)的單例可輕松地解決兩個(gè)問題:
①、線程安全問題。因?yàn)镴ava虛擬機(jī)在加載枚舉類的時(shí)候,會(huì)使用ClassLoader的loadClass方法,這個(gè)方法使用了同步代碼塊來保證線程安全。
②、避免反序列化破壞單例。因?yàn)槊杜e的反序列化并不通過反射實(shí)現(xiàn)。
4)枚舉可與數(shù)據(jù)庫交互
我們可以配合Mybatis將數(shù)據(jù)庫字段轉(zhuǎn)換為枚舉類型。現(xiàn)在假設(shè)有一個(gè)數(shù)據(jù)庫字段check_type的類型如下:
`check_type`?int(1)?DEFAULT?NULL?COMMENT?'檢查類型(1:未通過、2:通過)',它對應(yīng)的枚舉類型為CheckType,代碼如下:
public?enum?CheckType?{NO_PASS(0,?"未通過"),?PASS(1,?"通過");private?int?key;private?String?text;private?CheckType(int?key,?String?text)?{this.key?=?key;this.text?=?text;}public?int?getKey()?{return?key;}public?String?getText()?{return?text;}private?static?HashMap<Integer,CheckType>?map?=?new?HashMap<Integer,CheckType>();static?{for(CheckType?d?:?CheckType.values()){map.put(d.key,?d);}}public?static?CheckType?parse(Integer?index)?{if(map.containsKey(index)){return?map.get(index);}return?null;} }CheckType枚舉類比我們剛開始見到的那個(gè)Chenmo枚舉類要復(fù)雜一些。
第一,CheckType新添加了構(gòu)造方法,還有兩個(gè)字段,key為int型,text為String型。
第二,CheckType中有一個(gè)public static CheckType parse(Integer index)方法,可將一個(gè)Integer通過key的匹配轉(zhuǎn)化為枚舉類型。
那么現(xiàn)在,我們可以在Mybatis的配置文件中使用typeHandler將數(shù)據(jù)庫字段轉(zhuǎn)化為枚舉類型。
<resultMap?id="CheckLog"?type="com.entity.CheckLog"><id?property="id"?column="id"/><result?property="checkType"?column="check_type"?typeHandler="com.CheckTypeHandler"></result> </resultMap>其中checkType字段對應(yīng)的類如下:
public?class?CheckLog?implements?Serializable?{private?String?id;private?CheckType?checkType;public?String?getId()?{return?id;}public?void?setId(String?id)?{this.id?=?id;}public?CheckType?getCheckType()?{return?checkType;}public?void?setCheckType(CheckType?checkType)?{this.checkType?=?checkType;} }CheckTypeHandler轉(zhuǎn)換器的類源碼如下:
public?class?CheckTypeHandler?extends?BaseTypeHandler<CheckType>?{@Overridepublic?CheckType?getNullableResult(ResultSet?rs,?String?index)?throws?SQLException?{return?CheckType.parse(rs.getInt(index));}@Overridepublic?CheckType?getNullableResult(ResultSet?rs,?int?index)?throws?SQLException?{return?CheckType.parse(rs.getInt(index));}@Overridepublic?CheckType?getNullableResult(CallableStatement?cs,?int?index)?throws?SQLException?{return?CheckType.parse(cs.getInt(index));}@Overridepublic?void?setNonNullParameter(PreparedStatement?ps,?int?index,?CheckType?val,?JdbcType?arg3)?throws?SQLException?{ps.setInt(index,?val.getKey());} }CheckTypeHandler 的核心功能就是調(diào)用CheckType枚舉類的parse()方法對數(shù)據(jù)庫字段進(jìn)行轉(zhuǎn)換。
5)枚舉會(huì)比靜態(tài)常量更消耗內(nèi)存嗎?
說完枚舉最常用的4個(gè)知識點(diǎn)后,我們來討論一下“枚舉會(huì)比靜態(tài)常量更消耗內(nèi)存嗎?”這個(gè)話題——知乎上有人問這樣的問題,還有很多人參與回答。
按我的理解,問這個(gè)問題的人就好像是在問“0.000,001”比“0.000,000,99”大嗎?你說是嗎?
總結(jié)
以上是生活随笔為你收集整理的Java枚举:小小enum,优雅而干净的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: chrome jsonView插件安装
- 下一篇: 深入浅出,Spring 框架和 Spri