检查Java中是否存在枚举

Dan*_*nny 55 java string enums compare

无论如何通过将枚举与给定的字符串进行比较来检查枚举是否存在?我似乎找不到任何这样的功能.我可以尝试使用该valueOf方法并捕获异常,但我被教导说捕获运行时异常并不是一种好的做法.有人有什么想法吗?

Jon*_*eet 62

如果我需要这样做,我有时会建立一个Set<String>名字,甚至是我自己的Map<String,MyEnum>- 然后你可以检查一下.

值得注意的几点:

  • 在静态初始化程序中填充任何此类静态集合.不要使用变量初始化程序,然后依赖它在枚举构造函数运行时执行 - 它不会!(在静态初始化程序之前,枚举构造函数是第一个要执行的东西.)
  • 尽量避免values()频繁使用- 每次都必须创建并填充新数组.要迭代所有元素,使用EnumSet.allOf哪个元素对于没有大量元素的枚举更有效.

示例代码:

import java.util.*;

enum SampleEnum {
    Foo,
    Bar;

    private static final Map<String, SampleEnum> nameToValueMap =
        new HashMap<String, SampleEnum>();

    static {
        for (SampleEnum value : EnumSet.allOf(SampleEnum.class)) {
            nameToValueMap.put(value.name(), value);
        }
    }

    public static SampleEnum forName(String name) {
        return nameToValueMap.get(name);
    }
}

public class Test {
    public static void main(String [] args)
        throws Exception { // Just for simplicity!
        System.out.println(SampleEnum.forName("Foo"));
        System.out.println(SampleEnum.forName("Bar"));
        System.out.println(SampleEnum.forName("Baz"));
    }
}
Run Code Online (Sandbox Code Playgroud)

当然,如果你只有几个名字,这可能有点过分 - 当n足够小时,O(n)解决方案通常胜过O(1)解决方案.这是另一种方法:

import java.util.*;

enum SampleEnum {
    Foo,
    Bar;

    // We know we'll never mutate this, so we can keep
    // a local copy.
    private static final SampleEnum[] copyOfValues = values();

    public static SampleEnum forName(String name) {
        for (SampleEnum value : copyOfValues) {
            if (value.name().equals(name)) {
                return value;
            }
        }
        return null;
    }
}

public class Test {
    public static void main(String [] args)
        throws Exception { // Just for simplicity!
        System.out.println(SampleEnum.forName("Foo"));
        System.out.println(SampleEnum.forName("Bar"));
        System.out.println(SampleEnum.forName("Baz"));
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 好吧,它返回一个数组......并且它不能保护你不要改变那个数组......并且后续的调用者不会受到这种阻碍.除此之外,看看JRE来源:) (10认同)
  • 哎呀,抱歉 - 是的,只是检查一下自己.然后反编译一个枚举:)它使用clone(),这可能很快,但没有那么快就完全不需要了... (2认同)

Mic*_*ers 47

我不认为有一种内置的方法可以做到这一点而不会捕获异常.你可以改用这样的东西:

public static MyEnum asMyEnum(String str) {
    for (MyEnum me : MyEnum.values()) {
        if (me.name().equalsIgnoreCase(str))
            return me;
    }
    return null;
}
Run Code Online (Sandbox Code Playgroud)

编辑:正如Jon Skeet所说,values()每次调用它时都会克隆一个私有后备数组.如果性能至关重要,您可能只想调用values()一次,缓存数组并迭代它.

此外,如果您的枚举具有大量值,则Jon Skeet的地图替代方案可能比任何数组迭代都更好.


рüф*_*ффп 36

我最喜欢的lib之一:Apache Commons.

EnumUtils能做到这一点很容易.

下面的示例验证具有该库的Enum:

public enum MyEnum {
    DIV("div"), DEPT("dept"), CLASS("class");

    private final String val;

    MyEnum(String val) {
    this.val = val;
    }

    public String getVal() {
    return val;
    }
}


MyEnum strTypeEnum = null;

// test if String str is compatible with the enum 
// e.g. if you pass str = "div", it will return false. If you pass "DIV", it will return true.
if( EnumUtils.isValidEnum(MyEnum.class, str) ){
    strTypeEnum = MyEnum.valueOf(str);
}
Run Code Online (Sandbox Code Playgroud)

  • 在我看来,Apache Commons必须是一个"常见的基础依赖",可以添加到任何Java项目中;) (3认同)

nos*_*nos 6

我不知道为什么有人告诉你捕获运行时异常很糟糕.

使用valueOf和捕获IllegalArgumentException可以将字符串转换/检查为枚举.

  • 不,不是,IMO.这是通过异常测试非异常情况 - 在正常的非错误条件下使用它们进行流量控制.这是对IMO异常的极少使用,并且可能会对性能产生重大影响.异常在性能方面通常很好,因为它们不应该发生 - 但是当你将它们用于非错误条件时,那些*看起来像它应该快速运行的代码可能会陷入困境. (22认同)
  • 有趣的事情 - 基于这种观点(我通常也会分享),我决定使用Apache Commons`EnumUtils.isValidEnum`方式让它变得"干净".并猜测如何实现`EnumUtils.isValidEnum` - 当然捕捉`IllegalArgumentException` :-) (10认同)

Seb*_*ber 6

根据Jon Skeet的回答,我做了一个允许在工作中轻松完成的课程:

import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;

import java.util.EnumSet;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * <p>
 * This permits to easily implement a failsafe implementation of the enums's valueOf
 * Better use it inside the enum so that only one of this object instance exist for each enum...
 * (a cache could solve this if needed)
 * </p>
 *
 * <p>
 * Basic usage exemple on an enum class called MyEnum:
 *
 *   private static final FailSafeValueOf<MyEnum> FAIL_SAFE = FailSafeValueOf.create(MyEnum.class);
 *   public static MyEnum failSafeValueOf(String enumName) {
 *       return FAIL_SAFE.valueOf(enumName);
 *   }
 *
 * </p>
 *
 * <p>
 * You can also use it outside of the enum this way:
 *   FailSafeValueOf.create(MyEnum.class).valueOf("EnumName");
 * </p>
 *
 * @author Sebastien Lorber <i>(lorber.sebastien@gmail.com)</i>
 */
public class FailSafeValueOf<T extends Enum<T>> {

    private final Map<String,T> nameToEnumMap;

    private FailSafeValueOf(Class<T> enumClass) {
        Map<String,T> map = Maps.newHashMap();
        for ( T value : EnumSet.allOf(enumClass)) {
            map.put( value.name() , value);
        }
        nameToEnumMap = ImmutableMap.copyOf(map);
    }

    /**
     * Returns the value of the given enum element
     * If the 
     * @param enumName
     * @return
     */
    public T valueOf(String enumName) {
        return nameToEnumMap.get(enumName);
    }

    public static <U extends Enum<U>> FailSafeValueOf<U> create(Class<U> enumClass) {
        return new FailSafeValueOf<U>(enumClass);
    }

}
Run Code Online (Sandbox Code Playgroud)

单元测试:

import org.testng.annotations.Test;

import static org.testng.Assert.*;


/**
 * @author Sebastien Lorber <i>(lorber.sebastien@gmail.com)</i>
 */
public class FailSafeValueOfTest {

    private enum MyEnum {
        TOTO,
        TATA,
        ;

        private static final FailSafeValueOf<MyEnum> FAIL_SAFE = FailSafeValueOf.create(MyEnum.class);
        public static MyEnum failSafeValueOf(String enumName) {
            return FAIL_SAFE.valueOf(enumName);
        }
    }

    @Test
    public void testInEnum() {
        assertNotNull( MyEnum.failSafeValueOf("TOTO") );
        assertNotNull( MyEnum.failSafeValueOf("TATA") );
        assertNull( MyEnum.failSafeValueOf("TITI") );
    }

    @Test
    public void testInApp() {
        assertNotNull( FailSafeValueOf.create(MyEnum.class).valueOf("TOTO") );
        assertNotNull( FailSafeValueOf.create(MyEnum.class).valueOf("TATA") );
        assertNull( FailSafeValueOf.create(MyEnum.class).valueOf("TITI") );
    }

}
Run Code Online (Sandbox Code Playgroud)

请注意,我使用Guava制作了一个ImmutableMap但实际上你可以使用一个普通的地图我认为因为地图永远不会返回...