java 我可以根据其字段的值获取枚举吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15370288/
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
Can I get an enum based on the value of its field?
提问by Jethro
I want to get a specific enum based on its field value.
我想根据其字段值获取特定的枚举。
Enum:
枚举:
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;
}
}
Getting a new Enum:
获得一个新的枚举:
aStringRecivedFromJson = "Anti Social Behaviour"
CrimeCategory crimeCategoryEnum;
crimeCategoryEnum = CrimeCategory.valueOf(aStringRecivedFromJson);
I have been trying to work out a way for the above bring back a an enum so it can be passed stored in a HashMap
with other Crime
information.
我一直在尝试为上述方法找到一种方法,将一个枚举带回来,以便它可以HashMap
与其他Crime
信息一起存储在 a 中。
Expected Result: ASBO
预期结果: ASBO
回答by assylias
For reference, here is an alternative solution with a HashMap:
作为参考,这是一个带有 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;
}
}
回答by sharakan
Add a static method to the CrimeCategory
enum:
向CrimeCategory
枚举添加静态方法:
public static CrimeCategory valueOf(String name) {
for (CrimeCategory category : values()) {
if (category.category.equals(name)) {
return category;
}
}
throw new IllegalArgumentException(name);
}
回答by scottb
Static factory methods that return an enum constant based on the value of an instance field take on one of the two forms described in the other answers: a solution based on iterating the enum values, or a solution based on a HashMap
.
基于实例字段值返回枚举常量的静态工厂方法采用其他答案中描述的两种形式之一:基于迭代枚举值的解决方案,或基于HashMap
.
For enums with a small number of constants, the iterative solution should be as performant as the HashMap
solution (which requires calculation of the hash code, matching it to a bucket, and assuming that there will be no hash collisions).
对于常量较少的枚举,迭代解决方案应该和HashMap
解决方案一样高效(这需要计算散列码,将其匹配到一个桶,并假设不会有散列冲突)。
For larger enums, the map-based solution will be more performant (but requires storage space in memory). However, if the factory method is invoked infrequently then the overall performance improvement by using a map could still be immeasurably small.
对于较大的枚举,基于映射的解决方案将具有更高的性能(但需要内存中的存储空间)。但是,如果不经常调用工厂方法,那么使用映射的整体性能改进仍然是无法估量的。
The overall decision to use an iterative lookup or a map-based lookup for the static factory method will ultimately depend on your requirements and the environment. It is never wrong to start with an iterative lookup and then change to a map-based implementation if profiling shows an actual performance problem.
对静态工厂方法使用迭代查找还是基于地图的查找的总体决定最终取决于您的要求和环境。如果分析显示实际性能问题,从迭代查找开始,然后更改为基于映射的实现永远不会错。
Lastly, since Java 8, the Streams
API enables a pipeline-based solution for mapping (that should have performance similar to the iterative solution). For example, say that you want to create an interface that you could use on any enum class to express your intent that it should be matchable by one of its instance fields. Let's call this interface Matchable
. This interface defines a method which returns the instance field on which you want to match (eg. getField()
). This interface can also define a static factory method to return a constant from any implementing enum class:
最后,从 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()));
}
}
Now, any enum class that you define that implements Matchable
can use the Matchable.forToken()
static factory method to find the enum constant whose instance field value matches the supplied parameter.
现在,您定义的任何实现的枚举类Matchable
都可以使用Matchable.forToken()
静态工厂方法来查找实例字段值与提供的参数匹配的枚举常量。
The generic type declaration E extends Enum<E> & Matchable
assures that the type token passed to the method as a parameter will be for an enum class that implements Matchable
(otherwise the code won't compile).
泛型类型声明E extends Enum<E> & Matchable
确保作为参数传递给方法的类型标记将用于实现的枚举类Matchable
(否则代码将无法编译)。
回答by michalk
Assylias answer is great. Though I would return an Optional
from the factory method to let the client deal with the situation when enum could not be found (of course throwing IllegalArgumentException
might be better if you use this enum internally and you think that invoking this method with wrong argument will never happen - this is your choice).
Assylias 的回答很棒。虽然我会Optional
从工厂方法返回一个让客户端处理找不到枚举的情况(当然,IllegalArgumentException
如果你在内部使用这个枚举并且你认为用错误的参数调用这个方法永远不会发生,抛出可能会更好 -这是你的选择)。
And also I would wrap the Map
into unmodifiable wrapper to not modify it somewhere by accident inside your enum (the Map
is private but someone could modify it later when adding new functionalities - it will at least force to think about it) :
而且我会将Map
它包装到不可修改的包装器中,以免在您的枚举中意外修改它(这Map
是私有的,但有人可以稍后在添加新功能时对其进行修改 - 它至少会强制考虑它):
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;
static {
Map<String, CrimeCategory> crimeCategoryMap = Arrays.stream(values())
.collect(toMap(cg -> cg.category, e -> e));
MAP = Collections.unmodifiableMap(crimeCategoryMap);
}
private final String category;
private CrimeCategory(String category) {
this.category = category;
}
public static Optional<CrimeCategory> of(final String name) {
return Optional.ofNullable(MAP.get(name));
}
}