2013-03-12 101 views
16

我想根據其字段值來獲取特定的枚舉。我可以根據其字段的值獲取枚舉嗎?

枚舉:

public enum CrimeCategory { 
    ASBO ("Anti Social Behaviour"), 
    BURG ("Burglary"), 
    CRIMDAM ("Criminal Damage And Arson"), 
    DRUGS ("Drugs"), 
    OTHTHEFT ("Other Theft"), 
    PUPDISOR ("Public Disorder And Weapons"), 
    ROBBERY ("Robbery"), 
    SHOPLIF ("Shoplifting"), 
    VEHICLE ("Vehicle Crime"), 
    VIOLENT ("Violent Crime"), 
    OTHER ("Other Crime"); 

    private String category; 


    private CrimeCategory (String category) { 
     this.category = category; 
    } 

    public String returnString() { 
     return category; 
    } 
} 


獲得一個新的枚舉:

aStringRecivedFromJson = "Anti Social Behaviour" 
CrimeCategory crimeCategoryEnum; 
crimeCategoryEnum = CrimeCategory.valueOf(aStringRecivedFromJson); 

我一直在試圖制定出上述的方式帶回一個枚舉,因此可以通過存儲在HashMap與其他Crime信息。

預期結果:ASBO

+2

toString()將爲您提供Enum的字符串表示形式,除非您覆蓋它。 – Marvo 2013-03-12 19:28:10

+0

@Jethro fyi,你不是真的用這個示例代碼「初始化一個新枚舉」。事實上,你不能那樣做,因爲Java中的枚舉實際上是單例。你真的在查找現有的枚舉值。 – sharakan 2013-03-12 19:38:37

回答

20

作爲參考,這裏是具有一個HashMap的替代解決方案:

enum CrimeCategory { 
    ASBO("Anti Social Behaviour"), 
    BURG("Burglary"), 
    CRIMDAM("Criminal Damage And Arson"), 
    DRUGS("Drugs"), 
    OTHTHEFT("Other Theft"), 
    PUPDISOR("Public Disorder And Weapons"), 
    ROBBERY("Robbery"), 
    SHOPLIF("Shoplifting"), 
    VEHICLE("Vehicle Crime"), 
    VIOLENT("Violent Crime"), 
    OTHER("Other Crime"); 

    private static final Map<String, CrimeCategory> map = new HashMap<>(values().length, 1); 

    static { 
    for (CrimeCategory c : values()) map.put(c.category, c); 
    } 

    private final String category; 

    private CrimeCategory(String category) { 
    this.category = category; 
    } 

    public static CrimeCategory of(String name) { 
    CrimeCategory result = map.get(name); 
    if (result == null) { 
     throw new IllegalArgumentException("Invalid category name: " + name); 
    } 
    return result; 
    } 
} 
+0

非常感謝你,如果如果更頻繁地調用類別值,我將包含'HashMap'。目前只有在點擊地圖標記時纔會調用它,因此性能目前沒問題 – Jethro 2013-03-13 14:55:57

15

添加靜態方法將CrimeCategory枚舉:

public static CrimeCategory valueOf(String name) { 
    for (CrimeCategory category : values()) { 
     if (category.category.equals(name)) { 
      return category; 
     } 
    }  
    throw new IllegalArgumentException(name); 
} 
+4

或者,如果性能很關鍵,可以使用包含映射的靜態HashMap ... – assylias 2013-03-12 19:59:25

+1

確實......我不確定實際的枚舉值是在靜態初始化塊運行之前還是之後創建的,所以計算出I保持簡單。 – sharakan 2013-03-12 20:08:23

+0

@sharakan是的,從枚舉構造函數向'enum'的靜態字段'Map'自我註冊將NPE。 (解決方案:把靜態放在一個嵌套的類或循環中,通過靜態初始化程序中的value()將它們放到地圖中。) – 2013-03-12 20:30:44

2

靜態工廠方法返回基於實例字段的值的枚舉常量採用其他答案中描述的兩種形式之一:基於i的解決方案評估枚舉值,或基於HashMap的解決方案。

對於具有少量常量的枚舉,迭代解決方案應該與HashMap解決方案(需要計算哈希代碼,將其與桶進行匹配以及假設不會存在哈希衝突)一樣具有性能。

對於較大的枚舉,基於映射的解決方案將更具性能(但需要在內存中存儲空間)。但是,如果工廠方法不經常被調用,那麼通過使用映射的整體性能改進仍然可能非常小。

對靜態工廠方法使用迭代查找或基於映射的查找的總體決策最終取決於您的需求和環境。從迭代查找開始,然後在分析顯示實際性能問題時更改爲基於地圖的實現永遠不會錯。

最後,自Java 8以來,Streams API支持基於管線的映射解決方案(應該具有與迭代解決方案類似的性能)。例如,假設你想創建一個可以在任何枚舉類上使用的接口來表達你的意圖,即它應該可以通過它的一個實例字段匹配。我們稱這個接口爲Matchable。該接口定義了一個方法,該方法返回要匹配的實例字段(例如getField())。該接口還可以定義一個靜態工廠方法從任何執行枚舉類返回一個常量:

interface Matchable { 

    Object getField(); 

    public static <E extends Enum<E> & Matchable> E forToken(Class<E> cls, Object token) { 

     return Stream.of(cls.getEnumConstants()) 
      .filter(e -> e.getField().equals(token)) 
      .findFirst() 
      .orElseThrow(() -> new IllegalArgumentException("Unknown token '" + 
        token + "' for enum " + cls.getName())); 
    } 
} 

現在,任何枚舉類,定義了實現Matchable可以使用Matchable.forToken()靜態工廠方法找到枚舉常量,其實例字段值與提供的參數匹配。

通用類型聲明E extends Enum<E> & Matchable確保作爲參數傳遞給方法的類型標記將用於實現Matchable(否則代碼將不會編譯)的枚舉類。