java 按值查找枚举的正确方法
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4886973/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
The proper way to look up an enum by value
提问by Ray
I have several Java enums that looks something like below (edited for confidentiality, etc).
In each case, I have a lookup method that I'm really not satisfied with; in the example below, it is findByChannelCode
.
我有几个 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;
}
}
The problem is, I feel silly doing these linear lookups when I could just be using a HashMap<String, PresentationChannel>
. So I thought of the solution below, but it's a little messier that I would hope and, more to the point, I didn't care to re-invent the wheel when surely someone else has come across this. I wanted to get some of the sage wisdom of this group: what is the proper way to index an enum by value?
问题是,当我可以只使用HashMap<String, PresentationChannel>
. 所以我想到了下面的解决方案,但我希望它有点混乱,更重要的是,当肯定有人遇到这个问题时,我不想重新发明轮子。我想获得该组的一些智慧:按值索引枚举的正确方法是什么?
My solution:
我的解决方案:
ImmutableMap<String, PresentationChannel> enumMap = Maps.uniqueIndex(ImmutableList.copyOf(PresentationChannel.values()), new Function<PresentationChannel, String>() {
public String apply(PresentationChannel input) {
return input.getChannelCode();
}});
and, in the enum:
并且,在枚举中:
public static PresentationChannel findByChannelCode(String channelCode) {
return enumMap.get(channelCode);
}
采纳答案by gustafc
I wanted to get some of the sage wisdom of this group: what is the proper way to index an enum by value?
我想获得该组的一些智慧:按值索引枚举的正确方法是什么?
Quite possibly not doing it at all.
很可能根本不这样做。
While hash tables provide O(1)
lookup, they also have quite a large constant overhead (for hash calculations etc), so for small collections a linear search may well be faster (if "the efficient way" is your definition of "the proper way").
虽然哈希表提供O(1)
查找,但它们也有相当大的常量开销(用于哈希计算等),因此对于小型集合,线性搜索可能会更快(如果“有效方式”是您对“正确方式”的定义)。
If you just want a DRY way to do it, I suppose Guava's Iterables.find
is an alternative:
如果你只是想要一种干的方式来做到这一点,我想番石榴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);
回答by Puce
I think you're using non-JDK classes here right?
我认为您在这里使用的是非 JDK 类,对吗?
A similar solution with JDK API:
使用 JDK API 的类似解决方案:
private static final Map<String, PresentationChannel> channels = new HashMap<String, PresentationChannel>();
static{
for (PresentationChannel channel : values()){
channels.put(channel.getChannelCode(), channel);
}
}
回答by pamo
I was looking for something similar and found on this sitea simple, clean and straight to the point way. Create and initialize a static final map inside your enum and add a static method for the lookup, so it would be something like:
我正在寻找类似的东西,并在这个网站上找到了一种简单、干净、直截了当的方式。在枚举中创建并初始化一个静态最终映射,并为查找添加一个静态方法,因此它类似于:
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);
}
}
回答by Nicolas
回答by bestsss
for few values that's ok, iteration through the values array(). One note only: use smth like that. values()
clones the array on each invocation.
对于一些没问题的值,迭代值数组()。只有一个注意事项:像那样使用 smth。values()
在每次调用时克隆数组。
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;
}
if you have more Channels.
如果你有更多的频道。
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);
}
Edit:
编辑:
So implement an helper interface, like shown below, another example why java syntax generics blows and sometimes - better not used.
因此,实现一个帮助器接口,如下所示,另一个例子,为什么 java 语法泛型会爆炸,有时 - 最好不要使用。
Usage PresentationChannel channel = EnumRepository.get(PresentationChannel.class, "A");
There will be overhead but well, it's quite fool proof.
用法PresentationChannel channel = EnumRepository.get(PresentationChannel.class, "A");
会有开销,但很好,这是非常简单的证明。
public interface Identifiable<T> {
T getId();
public static class EnumRepository{
private static final ConcurrentMap<Class<? extends Identifiable<?>>, Map<?, ? extends Identifiable<?>>> classMap = new ConcurrentHashMap<Class<? extends Identifiable<?>>, Map<?,? extends Identifiable<?>>>(16, 0.75f, 1);
@SuppressWarnings("unchecked")
public static <ID, E extends Identifiable<ID>> E get(Class<E> clazz, ID value){
Map<ID, E> map = (Map<ID, E>) classMap.get(clazz);
if (map==null){
map=buildMap(clazz);
classMap.putIfAbsent(clazz, map);
}
return map.get(value);
}
private static <ID, E extends Identifiable<ID>> Map<ID, E> buildMap( Class<E> clazz){
E[] enumConsts = clazz.getEnumConstants();
if (enumConsts==null)
throw new IllegalArgumentException(clazz+ " is not enum");
HashMap<ID, E> map = new HashMap<ID, E>(enumConsts.length*2);
for (E e : enumConsts){
map.put(e.getId(), e);
}
return map;
}
}
}
enum X implements Identifiable<String>{
...
public String getId(){...}
}
Minor warning: if you put Identifiable somewhere out there, and many projects/wepapp depend on it (and share it) and so on, it's possible to leak classes/classloaders.
小警告:如果您将 Identifiable 放在某个地方,并且许多项目/wepapp 依赖于它(并共享它)等等,则可能会泄漏类/类加载器。
回答by rajah9
Here is another way to implement an unmodifiable map:
这是实现不可修改映射的另一种方法:
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);
}
You can use EnumMap.get(someCodeAthroughE)
to quickly retrieve the ChannelCode. If the expression is null then your someCodeAthroughE
was not found.
您可以使用它EnumMap.get(someCodeAthroughE)
来快速检索 ChannelCode。如果表达式为空,则someCodeAthroughE
未找到您的。
回答by Kevin Stembridge
If you are expecting the provided channelCode to always be valid then you can just try and get the correct instance of the enum using the valueOf() method. If the provided value is invalid you can return null or propagate the exception.
如果您希望提供的 channelCode 始终有效,那么您可以尝试使用 valueOf() 方法获取枚举的正确实例。如果提供的值无效,您可以返回 null 或传播异常。
try {
return PresentationChannel.valueOf(channelCode);
catch (IllegalArgumentException e) {
//do something.
}