欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

全面解讀Java中的枚舉類型enum的使用

 更新時間:2016年04月27日 08:58:45   作者:xieyu_zy  
這篇文章主要介紹了Java中的枚舉類型enum的使用,開始之前先講解了枚舉的用處,然后還舉了枚舉在操作數(shù)據(jù)庫時的實例,需要的朋友可以參考下

關(guān)于枚舉
大多數(shù)地方寫的枚舉都是給一個枚舉然后例子就開始switch,可是我想說,我代碼里頭來源的數(shù)據(jù)不太可能就是枚舉,通常是字符串或數(shù)字,比如一個SQL我解析后首先判定SQL類型,通過截取SQL的token,截取出來可能是SELECT、DELETE、UPDATE、INSERT、ALTER等等,但是都是字符串,此時我想用枚舉就不行了,我要將字符串轉(zhuǎn)換成枚舉怎么轉(zhuǎn)呢,類似的情況還有從數(shù)據(jù)庫取出數(shù)據(jù)根據(jù)一些類型做判定,從頁面?zhèn)魅霐?shù)據(jù),根據(jù)不同的類型做不同的操作,但是都是字符串,不是枚舉,悲劇的是我很少看到有人寫到這個東西;所以我把它寫下來,希望有人能用到。

首先為什么要用枚舉?我們在什么時候用枚舉比較好,用枚舉有啥優(yōu)勢?

我認(rèn)為哈,當(dāng)你在一些一個范疇類,并可列舉,不變化的類型,用以指導(dǎo)程序向不同的地方路由,用枚舉是較好的選擇;

聽起來有點繞,不過有個例子也許可以明白,例如:

我們可以列舉下日常工作日所做的事情:

上班、開會、吃飯、睡覺等

我們可以列舉醫(yī)院五官科需要檢查人的部位:

眼睛、鼻子、耳朵、嘴巴等

這些都是可以被列舉的,且每種事情我們要用不同的方式去做;

當(dāng)然你可以說:

1、可以用動態(tài)方法分派,通過配置文件或annotation;

2、可以使用常量來達(dá)到類似的效果;

3、直接通過字符串的equals來表達(dá),用if else來表達(dá)

如果用配置加方法分派來做,是靈活,便于修改;但是如果在很多不經(jīng)常修改的參數(shù)上,我們用這中方式往往增加配置的負(fù)擔(dān),并且當(dāng)你需要看系統(tǒng)邏輯的時候,需要需要一遍看配置一遍看代碼;不過,如果參數(shù)是可動態(tài)變換的信息,用配置是正確的選擇;

而常量的使用,通常在switch case的時候都是數(shù)字,字符串在java中是不能做switch case的,使用常量的目的比case 1、case 2 …這種增加了可讀性;但是字符串?dāng)?shù)據(jù)也麻煩,除非再映射一次,那沒那個必要,其實枚舉也差不多是幫你映射了一次,只是它將代碼封裝了而已吧了,既然他弄好了,而且語法上支持,干嘛不用呢!其次,常量雖然增加了可讀性,不過他沒有范疇和管理類型的概念,即一個枚舉的定義會定義個范疇,可以很好的將這個范圍所需要的東西列舉出來,而常量通常是些自己定義的一些池,放在一些公共類中或隨機定義,都是比較零散的,并且枚舉在switch的時候就明確定義好了就在鎖列舉的范圍內(nèi)case,既可以控制好系統(tǒng),增加可讀性,并且可以隨時查看這個范疇的枚舉信息到底有那些,達(dá)到類似看配置文件的作用;不過還是回到那句話,如果參數(shù)是可變的,那么就不適合做枚舉,枚舉是一定是可列舉的,或者說當(dāng)前系統(tǒng)考慮范圍是可以被枚舉的,例如上面的醫(yī)院五官科,可能還有很多沒有列舉到,但是當(dāng)前醫(yī)院只處理幾個部位,不處理其他的,就是這個道理;什么是可變的呢,例如URL參數(shù)來分派到對應(yīng)方法,不可能大家加一段邏輯就去加一個枚舉,加一個case,此時用【配置+動態(tài)方法分派】更好,當(dāng)然配置可以用文件或annotation而已。

還有最土的就是,通過字符串equals,用if else來實現(xiàn),呵呵,這個并沒有什么不好,只是這個寫比較零散,其次,字符串匹配的equals每次匹配都需要對比每個字符,如果你的代碼中大量循環(huán),性能并不是很好,其余的看看上面的描述就更加清楚了;

其次,枚舉提供一種類型管理的組件,讓面向?qū)ο蟮捏w系更加完善,使得一些類型的管理既可配置化,并可以管理,在使用枚舉的地方都可以沿著枚舉的定義找到那些有處理過,那些沒處理過,而上述幾種很難做到;例如,數(shù)據(jù)庫的操作類型定義了10種,那么再判定的過程中就可以講枚舉像配置文件一樣看待,而又非常簡單的來管理。

最后,枚舉絕對是單例的,對比的性能和數(shù)字性能相當(dāng),既可以得到可讀性,也可以得到性能。


enum類型的基本使用
有了這樣的理論基礎(chǔ),我們下面就來看Java中的enum枚舉類型:
1、可以在enum中添加變量和方法

先來看一段代碼示例:

public enum State {
    Normal("正常態(tài)", 1), Update("已更新", 2), Deleted("已刪除", 3), Fired("已屏蔽", 4);
    // 成員變量
    private String name;
    private int index;

    // 構(gòu)造方法,注意:構(gòu)造方法不能為public,因為enum并不可以被實例化
    private State(String name, int index) {
      this.name = name;
      this.index = index;
    }

    // 普通方法
    public static String getName(int index) {
      for (State c : State .values()) {
        if (c.getIndex() == index) {
          return c.name;
        }
      }
      return null;
    }

    // get set 方法
    public String getName() {
      return name;
    }

    public void setName(String name) {
      this.name = name;
    }

    public int getIndex() {
      return index;
    }

    public void setIndex(int index) {
      this.index = index;
    }
  }

從上面的代碼中我們可以看到,定義完枚舉值,然后在其后面加上分號,接著就可以定義其他的變量、方法了。另外需要特別說明的是,enum中的構(gòu)造方法不可以用public標(biāo)識,這樣做是為了防止用戶實例化enum。

2、可以用來定義常量

先來回顧一下Java中如何定義常量吧,看下面一段代碼:

public static final int normalState = 1;
private static final int updateState = 2;

下面我們還可以用enum枚舉來代替上面的常量定義,代碼如下:

public enum State { 
 Normal, Update, Deleted, Fired
}

在Java中用enum來定義常量在語法上沒有什么優(yōu)勢,但是enum枚舉類型可以提供更多的操作功能。

3、在enum中實現(xiàn)接口

先來看下面一段代碼:

public interface ICanReadState {
    void read();

    String getState();
}

  public enum State implements ICanReadState {
    Normal("正常態(tài)", 1), Update("已更新", 2), Deleted("已刪除", 3), Fired("已屏蔽", 4);

    private String name;
    private int index;

    private State(String name, int index) {
      this.name = name;
      this.index = index;
    }

    // 接口方法1

    @Override
    public String getState() {
      return this.name;
    }

    // 接口方法2
    @Override
    public void read() {
      System.out.println(this.index + ":" + this.name);
    }
  }

和一般的類中使用接口一樣,enum枚舉中同樣可以繼承接口,并實現(xiàn)接口中的所有方法,這樣做的好處在于可以更方便地對枚舉中的值進(jìn)行排序、比較等操作,封裝性更好。

實例
我們先定義個簡單枚舉(這里只是個例子,就簡單定義3個變量了):

public enum SqlTypeEnum {
  INSERT , 
  UPDATE ,
  DELETE ,
  SELECT
}

此時解析SQL后,獲取出來一個token,我們要獲取這個token的枚舉怎么獲取呢?

這樣獲?。?/p>

String token = "select";
SqlTypeEnum sqlTypeEnum = SqlTypeEnum.valueOf(token.toUpperCase());

如果沒獲取到,java會拋出一個異常哦:IllegalArgumentException No enum const class SqlTypeEnum.XXX

我做大寫處理的原因是因為枚舉也是大寫的(當(dāng)然如果你的枚舉是小寫的,那你就小寫,不過混寫比較麻煩哈),其實valueOf就是調(diào)用了枚舉的底層映射:

201642785504527.jpg (575×287)

調(diào)用的時候會調(diào)用這個方法:

201642785619095.jpg (491×205)

所以內(nèi)部也是一個HashMap,呵呵!

拿到這個信息后,就可以做想要的操作了:

switch(sqlTypeEnum) {
 case INSERT:處理insert邏輯;break;
 case DELETE:處理delete邏輯;break;
 ....
}

OK,有些時候可能我們不想直接用INSERT、UPDATE這樣的字符串在交互中使用,因為很多時候命名規(guī)范的要求;

例如定義一些用戶操作類型:

1、保存用戶信息

2、通過ID獲取用戶基本信息

3、獲取用戶列表

4、通過ID刪除用戶信息

等等

我們可能定義枚舉會定義為:

public enum UserOptionEnum {
  SAVE_USER,
  GET_USER_BY_ID,
  GET_USER_LIST,
  DELETE_USER_BY_ID
}

但是系統(tǒng)的方法和一些關(guān)鍵字的配置,通常會寫成:

saveUser、getUserById、getUserById、deleteUserById

當(dāng)然各自有各自的規(guī)則,不過中間這層映射,你不想做,就一方面妥協(xié),要么枚舉名稱全部換掉,貌似挺奇怪的,要么方法名稱全部換掉,更加奇怪,要么自己做映射,可以,稍微麻煩點,其實也不麻煩?

我們首先寫個將枚舉下劃線風(fēng)格的數(shù)據(jù)轉(zhuǎn)換為駝峰的方法,放在一個StringUtils里面:

public static String convertDbStyleToJavaStyle(String dbStyleString , boolean firstUpper) {
    dbStyleString = dbStyleString.toLowerCase();
    String []tokens = dbStyleString.split("_");
    StringBuilder stringBuilder = new StringBuilder(128);
    int length = 0;
    for(String token : tokens) {
      if(StringUtils.isNotBlank(token)) {
        if(length == 0 && !firstUpper) {
          stringBuilder.append(token);
        }else {
          char c = token.charAt(0);
          if(c >= 'a' || c <= 'z') c = (char)(c - 32);
          stringBuilder.append(c);
          stringBuilder.append(token.substring(1));
        }
      }
      ++length;
    }
    return stringBuilder.toString();
  }

重載一個方法:

public static String convertDbStyleToJavaLocalStyle(String dbStyleString) {
    return convertDbStyleToJavaStyle(dbStyleString , false);
  }

然后定義枚舉:

public enum UserOptionEnum {
  SAVE_USER,
  GET_USER_BY_ID,
  GET_USER_LIST,
  DELETE_USER_BY_ID;
 
  private final static Map<String , UserOptionEnum> ENUM_MAP = new HashMap<String, UserOptionEnum>(64);
 
  static {
    for(UserOptionEnum v : values()) {
      ENUM_MAP.put(v.toString() , v); 
    }
  }
 
  public staticUserOptionEnum fromString(String v) {
    UserOptionEnum userOptionEnum = ENUM_MAP.get(v);
    return userOptionEnum == null ? DEFAULT :userOptionEnum;
  }
 
  public String toString() {
    String stringValue = super.toString();
    return StringUtil.convertDbStyleToJavaLocalStyle(stringValue);
  }
}

OK,這樣傳遞一個event參數(shù)讓如果是:saveUser,此時就用:

String event = "saveUser";//假如這里得到參數(shù)
UserOptionEnum enum = UserOptionEnum.fromString(event);

其實就是自己做了一個hashMap,我這加了一個fromString,因為枚舉有一些限制,有些方法不讓你覆蓋,比如valueOf方法就是這樣。

其實沒啥好講的了,非要說,再說說枚舉加一些自定義變量吧,其實枚舉除了是單例的外,其余的和普通類也相似,它也可以有構(gòu)造方法,只是默認(rèn)情況下不是而已,也可以提供自定義的變量,然后獲取set、get方法,但是如果有set的話,線程不是安全的哦,要注意這點;所以一般是構(gòu)造方法就寫好了:

public enum SqlTypeEnum {
  INSERT("insert into"),
  DELETE("delete from")
  ......省略;
 
  private String name;//定義自定義的變量
 
  private SqlTypeEnum(String name) {
   this.name = name;
  }
 
  public String getName() {
    return name;
  }
 
  public String toString() {
    return name + " 我靠";//重寫toString方法
 }
 //一般不推薦
 public void setName(String name) {
    this.name = name;
 }
}

調(diào)用下:

SqlTypeEnum sqlTypeEnum = SqlTypeEnum.valueOf("INSERT");
System.out.println(sqlTypeEnum);
System.out.println(sqlTypeEnum.getName());

不推薦也調(diào)用下:

sqlTypeEnum.setName("我靠");

在另一個線程:

SqlTypeEnum sqlTypeEnum = SqlTypeEnum.valueOf("INSERT");
System.out.println(sqlTypeEnum);
System.out.println(sqlTypeEnum.getName());

發(fā)現(xiàn)結(jié)果被改了,呵呵!

相關(guān)文章

  • java分布式流式處理組件Producer分區(qū)理論

    java分布式流式處理組件Producer分區(qū)理論

    這篇文章主要為大家介紹了java分布式流式處理組件Producer分區(qū)理論詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-03-03
  • 解決在SpringBoot中使用@Value取不到值的問題

    解決在SpringBoot中使用@Value取不到值的問題

    這篇文章主要給大家分享解決在SpringBoot中使用@Value取不到值的問題,文中有詳細(xì)的解決代碼供大家參考,具有一定的參考價值,需要的朋友可以參考下
    2023-09-09
  • JAVA面向?qū)ο笾^承?super入門解析

    JAVA面向?qū)ο笾^承?super入門解析

    在JAVA類中使用super來引用父類的成分,用this來引用當(dāng)前對象,如果一個類從另外一個類繼承,我們new這個子類的實例對象的時候,這個子類對象里面會有一個父類對象。怎么引用里面的父類對象呢?用super來引用,this指當(dāng)前對象的引用,super是當(dāng)前對象里面的父對象的引用
    2022-01-01
  • springboot的logging.group日志分組方法源碼流程解析

    springboot的logging.group日志分組方法源碼流程解析

    這篇文章主要為大家介紹了springboot的logging.group日志分組方法源碼流程解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-12-12
  • Java如何獲取對象屬性及對應(yīng)值

    Java如何獲取對象屬性及對應(yīng)值

    這篇文章主要介紹了Java如何獲取對象屬性及對應(yīng)值,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-11-11
  • 基于Spring Data Jest的Elasticsearch數(shù)據(jù)統(tǒng)計示例

    基于Spring Data Jest的Elasticsearch數(shù)據(jù)統(tǒng)計示例

    本篇文章主要介紹了基于Spring Data Jest的Elasticsearch數(shù)據(jù)統(tǒng)計示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-02-02
  • 詳談異步log4j2中的location信息打印問題

    詳談異步log4j2中的location信息打印問題

    這篇文章主要介紹了詳談異步log4j2中的location信息打印問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • IDEA無法打開Marketplace的三種解決方案(推薦)

    IDEA無法打開Marketplace的三種解決方案(推薦)

    這篇文章主要介紹了IDEA無法打開Marketplace的三種解決方案(推薦),本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-11-11
  • java創(chuàng)建txt文件并存入內(nèi)容

    java創(chuàng)建txt文件并存入內(nèi)容

    這篇文章主要為大家詳細(xì)介紹了java創(chuàng)建txt文件并存入內(nèi)容,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-08-08
  • 詳談java中int和Integer的區(qū)別及自動裝箱和自動拆箱

    詳談java中int和Integer的區(qū)別及自動裝箱和自動拆箱

    這篇文章主要介紹了詳談java中int和Integer的區(qū)別及自動裝箱和自動拆箱,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-08-08

最新評論