2011-07-27 83 views
7

我在我的代碼的多個枚舉:檢查是否枚舉類型包含具有給定名稱恆定

public enum First { a, b, c, d; } 

public enum Second { e, f, g; } 

我想有檢查以查看一個方法,如果一個值存在於使用的valueOf任何枚舉(),而不爲每個枚舉類型寫一個。例如(此代碼不能運行):

public boolean enumTypeContains(Enum e, String s) { 
    try { 
     e.valueOf(s); 
    } catch (IllegalArgumentException iae) { 
     return false; 
    } 
    return true; 
} 

用法:

enumTypeContains(First,"a"); // returns true 
enumTypeContains(Second,"b"); // returns false 

如何做這樣的事任何想法?

+0

我將所有三個答案(例如其中的代碼)添加到我的[github存儲庫stackoverflow-examples](https://github.com/ePaul/stackoverflow-examples/blob/master/src/de/fencing_game/paul /examples/EnumUtils.java)。 –

回答

8

這裏是您的解決方案:

public static boolean contains(Class<? extends Enum> clazz, String val) { 
    Object[] arr = clazz.getEnumConstants(); 
    for (Object e : arr) { 
     if (((Enum) e).name().equals(val)) { 
     return true; 
     } 
    } 
    return false; 
} 

它讓所有的枚舉的vaules和檢查,看它是否有與你分享傳入的參數名稱的值。如果是這樣,那麼它返回true ,否則返回false。

這已經過測試和工作。測試代碼:

public class Test { 
    public static void main(String[] args) { 
     System.out.println(contains(Haha.class, "Bad")); 
     System.out.println(contains(Haha.class, "Happy")); 
     System.out.println(contains(Haha.class, "Sad")); 
    } 

    static enum Haha { 
     Happy, Sad; 
    } 
} 

打印:

false 
true 
true 
+3

您可以在編譯時通過使第一個參數Class <?的類型限制爲'enum'類型。擴展Enum >'。那麼你不需要做任何運行時檢查。 – ColinD

+0

@Colin,感謝您的提示。不知道爲什麼我沒那麼早想到。 – jjnguy

+0

我想指出的是,通常使用異常來操縱程序的流程(例外情況除外)是一個壞主意。 – jjnguy

10

這應該工作:

public <E extends Enum<E>> boolean enumTypeContains(Class<E> e, String s) { 
    try { 
     Enum.valueOf(e, s); 
     return true; 
    } 
    catch(IllegalArgumentException ex) { 
     return false; 
    } 
} 

你就必須通過

enumTypeContains(First.class, "a"); 

我不知道,如果叫它簡單地搜索價值(就像從ji得到的答案一樣) nguy)可能比創建和拋出異常更快,但是。這將取決於你將得到多少次false,你有多少常量,以及堆棧跟蹤的時間長短(例如,這稱爲多深)。

如果您經常需要(對於相同的枚舉),最好創建一次HashSet或HashMap將名稱映射到枚舉值。

+0

調用'Enum.valueOf()'是否適用於所有枚舉類型? – jjnguy

+0

@jjn:http://download.oracle.com/javase/6/docs/api/java/lang/Enum.html#valueOf%28java.lang.Class,%20java.lang.String%29或者,更好的是,只是跑步和體驗自己。 – BalusC

+0

@jjnguy:是的。 – ColinD

3

我發現了另一個既不能迭代所有枚舉常量也不能拋出異常的變體......但它是實現特定的,即使用未記錄的方法。它適用於Sun的JDK 1.6.0_20(通過閱讀1.6.0_13中的源代碼)。

public static <E extends Enum<E>> boolean enumTypeContains(Class<E> e, String s) { 
    try { 
     Method enumDir = Class.class.getDeclaredMethod("enumConstantDirectory"); 
     enumDir.setAccessible(true); 
     Map<?,?> dir = (Map<?,?>)enumDir.invoke(e); 
     return dir.containsKey(s); 
    } 
    catch(NoSuchMethodException ex) { 
     throw new Error(ex); 
    } 
    catch(IllegalAccessException ex) { 
     throw new Error(ex); 
    } 
    catch(InvocationTargetException ex) { 
     throw new Error(ex.getCause()); 
    } 
} 

如果我們在java.lang包,這可能僅僅是這樣的:

public static <E extends Enum<E>> boolean enumTypeContains(Class<E> e, String s) { 
    return e.enumConstantDirectory().containsKey(s); 
} 

這使用方法Class.enumConstantDirectory(),其中(在第一次調用)創建和(後來只)返回地圖所有的枚舉常量作爲值,它們的名字作爲鍵。 (也可以手動創建這樣的地圖。)

此方法在內部使用Enum.valueOf(Class, String),據推測也由EnumType.valueOf(String)(取決於編譯器)使用。

在第一次調用enumConstantDirectorygetEnumConstants()時,私有幫助方法調用EnumType.values()(由編譯器實現)。結果然後重用於這兩個方法的後續調用。

+0

enumConstantDirectory()需要在'java.lang'中的規範解決了我的一個長期問題☺ –

相關問題