Java 按值查找枚举的正确方法

Java 按值查找枚举的正确方法,java,enums,Java,Enums,我有几个Java枚举,如下所示(为了保密等而编辑)。 在每种情况下,我都有一个查找方法,我真的不满意;在下面的示例中,它是findByChannelCode public enum PresentationChannel { ChannelA("A"), ChannelB("B"), ChannelC("C"), ChannelD("D"), ChannelE("E"); private String channelCode; Pres

我有几个Java枚举,如下所示(为了保密等而编辑)。 在每种情况下,我都有一个查找方法,我真的不满意;在下面的示例中,它是
findByChannelCode

public enum PresentationChannel {
    ChannelA("A"),
    ChannelB("B"),
    ChannelC("C"),
    ChannelD("D"),
    ChannelE("E");

    private String channelCode;

    PresentationChannel(String channelCode) {
        this.channelCode = channelCode;
    }

    public String getChannelCode() {
        return this.channelCode;
    }

    public PresentationChannel findByChannelCode(String channelCode) {
        if (channelCode != null) {
            for (PresentationChannel presentationChannel : PresentationChannel.values()) {
                if (channelCode.equals(presentationChannel.getChannelCode())) {
                    return presentationChannel;
                }
            }
        }

        return null;
    }
}
问题是,当我可以只使用
HashMap
时,我觉得做这些线性查找很愚蠢。所以我想到了下面的解决方案,但我希望它有点混乱,更重要的是,当肯定有其他人遇到这个问题时,我不想重新发明轮子。我想了解这个群体的一些智慧:什么是按值索引枚举的正确方法

我的解决方案:

ImmutableMap<String, PresentationChannel> enumMap = Maps.uniqueIndex(ImmutableList.copyOf(PresentationChannel.values()), new Function<PresentationChannel, String>() {
        public String apply(PresentationChannel input) {
            return input.getChannelCode();
        }});

如果希望提供的channelCode始终有效,则可以尝试使用valueOf()方法获取正确的枚举实例。如果提供的值无效,则可以返回null或传播异常

try {
    return PresentationChannel.valueOf(channelCode);
catch (IllegalArgumentException e) {
    //do something.
}

你为什么不把你的成员命名为A、B、C、D、E并使用它们呢?

我认为你在这里使用的是非JDK类,对吗

使用JDK API的类似解决方案:

private static final Map<String, PresentationChannel> channels = new HashMap<String, PresentationChannel>();

static{
  for (PresentationChannel channel : values()){
    channels.put(channel.getChannelCode(), channel);
  }
}
private static final Map channels=new HashMap();
静止的{
对于(PresentationChannel:values()){
channels.put(channel.getChannelCode(),channel);
}
}

对于少数确定的值,通过值数组()进行迭代。只需注意一点:像这样使用smth<代码>值()在每次调用时克隆数组

static final PresentationChannel[]  values=values(); 
static PresentationChannel getByCode(String code){
  if (code==null)
    return null;
  for(PresentationChannel channel: values) if (code.equals(channel.channelCode)) return channel;
  return null;
}
如果你有更多的频道

private static final Map<String code, PresentationChannel> map = new HashMap<String code, PresentationChannel>();
static{//hashmap sucks a bit, esp if you have some collisions so you might need to initialize the hashmap depending on the values count and w/ some arbitrary load factor
  for(PresentationChannel channel: values())  map.put(channel.channelCode, channel);
}

static PresentationChannel getByCode(String code){
  return map.get(code);
}

次要警告:如果您将可识别的映射放在某个地方,并且许多项目/wepapp依赖它(并共享它)等等,则可能会泄漏类/类加载器。

下面是实现不可修改映射的另一种方法:

protected static final Map<String, ChannelCode> EnumMap;
static { 
    Map<String, ChannelCode> tempMap = new HashMap<String, ChannelCode>();
    tempMap.put("A", ChannelA);
    tempMap.put("B", ChannelB);
    tempMap.put("C", ChannelC);
    tempMap.put("D", ChannelD);
    tempMap.put("E", ChannelE);
    EnumMap = Collections.unmodifiableMap(tempMap);
}
受保护的静态最终映射枚举映射;
静态{
Map tempMap=newhashmap();
tempMap.put(“A”,ChannelA);
tempMap.put(“B”,ChannelB);
tempMap.put(“C”,ChannelC);
tempMap.put(“D”,ChannelD);
tempMap.put(“E”,ChannelE);
EnumMap=Collections.unmodifiableMap(tempMap);
}
您可以使用
EnumMap.get(somecodeathrough)
快速检索通道代码。如果表达式为null,则找不到您的
SomeCodeAthrawe

我想了解这个群体的一些智慧:什么是按值索引枚举的正确方法

很可能根本不做

虽然哈希表提供
O(1)
查找,但它们也有相当大的固定开销(用于哈希计算等),因此对于小集合,线性搜索可能会更快(如果“有效方式”是您对“正确方式”的定义)

如果你只是想用一种干燥的方法来做,我想番石榴的
Iterables.find
是一种替代品:

return channelCode == null ? null : Iterables.find(Arrays.asList(values()),
    new Predicate<PresentationChannel>() {
        public boolean apply(PresentationChannel input) {
            return input.getChannelCode().equals(channelCode);
        }
    }, null);
返回channelCode==null?null:Iterables.find(Arrays.asList(values()),
新谓词(){
公共布尔应用(PresentationChannel输入){
返回input.getChannelCode().equals(channelCode);
}
},空);

我一直在寻找类似的东西,并找到了一种简单、干净、直截了当的方法。在枚举内创建并初始化静态最终映射,并为查找添加一个静态方法,因此类似于:

public enum PresentationChannel {
    ChannelA("A"),
    ChannelB("B"),
    ChannelC("C"),
    ChannelD("D"),
    ChannelE("E");

    private String channelCode;

    PresentationChannel(String channelCode) {
        this.channelCode = channelCode;
    }

    public String getChannelCode() {
        return this.channelCode;
    }

    private static final Map<String, PresentationChannel> lookup 
            = new HashMap<String, PresentationChannel>();

    static {
        for(PresentationChannel pc : EnumSet.allOf(PresentationChannel.class)) {
            lookup.put(pc.getChannelCode(), pc);
        }
    }

    public static PresentationChannel get(String channelCode) { 
        return lookup.get(channelCode); 
    }
}
公共枚举表示通道{
渠道A(“A”),
渠道B(“B”),
渠道C(“C”),
渠道D(“D”),
渠道E(“E”);
专用字符串信道码;
PresentationChannel(字符串通道代码){
this.channelCode=channelCode;
}
公共字符串getChannelCode(){
返回此.channelCode;
}
私有静态最终映射查找
=新HashMap();
静止的{
for(PresentationChannel pc:EnumSet.allOf(PresentationChannel.class)){
lookup.put(pc.getChannelCode(),pc);
}
}
公共静态表示通道获取(字符串通道代码){
返回lookup.get(channelCode);
}
}

你知道enumMap映射的是enum->Object,而不是相反?代码分析是否表明线性查找不充分?@bestsss,也许我的映射命名不好。它不是EnumMap,只是String->PresentationChannel(即value->instance)@trashgod的映射,在这里的示例中,为了清晰起见,只有几个实例。在实际的代码中,这个习惯用法的例子很多,而且查找也经常发生。。。我编辑答案是为了让您明白,基本上,您需要一个外部存储库和一个接口来实现。因为它们也可以像1,2,3,4那样,或者像ааааС1、ааааааааааааа2等等,即不是java标识符。我不希望名称与值紧密耦合。关于“我所。它不一定是最有效的。如果有不必要的开销,那就不好了。如果它容易出错,那也不好。我想我在想“Josh Bloch会做什么?”是的,这可能是“正确的方式”的一个很好的定义。@Ray,Joshua在java 1.4中炸掉了AbstractCollection.toArray()和新的ArrayList(Collection),从那时起,我就有了一些分歧。@gustafc我想提出一个更正/建议-EnumMap是一个非常有效的映射。不需要散列,因为它可以使用带有内部索引的数组作为枚举值。@确实如此,但它们仅在键为枚举时才起作用,这里不是这种情况。您可以使用
PresentationChannel.values()
return channelCode == null ? null : Iterables.find(Arrays.asList(values()),
    new Predicate<PresentationChannel>() {
        public boolean apply(PresentationChannel input) {
            return input.getChannelCode().equals(channelCode);
        }
    }, null);
public enum PresentationChannel {
    ChannelA("A"),
    ChannelB("B"),
    ChannelC("C"),
    ChannelD("D"),
    ChannelE("E");

    private String channelCode;

    PresentationChannel(String channelCode) {
        this.channelCode = channelCode;
    }

    public String getChannelCode() {
        return this.channelCode;
    }

    private static final Map<String, PresentationChannel> lookup 
            = new HashMap<String, PresentationChannel>();

    static {
        for(PresentationChannel pc : EnumSet.allOf(PresentationChannel.class)) {
            lookup.put(pc.getChannelCode(), pc);
        }
    }

    public static PresentationChannel get(String channelCode) { 
        return lookup.get(channelCode); 
    }
}