Have enum with inner fields, kind of map.
Now I need to get enum by its inner field.
Wrote this:
package test;
/**
* Test enum to test enum =)
*/
public enum TestEnum {
ONE(1), TWO(2), THREE(3);
private int number;
TestEnum(int number) {
this.number = number;
}
public TestEnum findByKey(int i) {
TestEnum[] testEnums = TestEnum.values();
for (TestEnum testEnum : testEnums) {
if (testEnum.number == i) {
return testEnu开发者_如何学Pythonm;
}
}
return null;
}
}
But it's not very efficient to look up through all enums each time I need to find appropriate instance.
Is there any other way to do the same?
You can use a static Map<Integer,TestEnum>
with a static
initializer that populates it with the TestEnum
values keyed by their number
fields.
Note that findByKey
has been made static
, and number
has also been made final
.
import java.util.*;
public enum TestEnum {
ONE(1), TWO(2), SIXTY_NINE(69);
private final int number;
TestEnum(int number) {
this.number = number;
}
private static final Map<Integer,TestEnum> map;
static {
map = new HashMap<Integer,TestEnum>();
for (TestEnum v : TestEnum.values()) {
map.put(v.number, v);
}
}
public static TestEnum findByKey(int i) {
return map.get(i);
}
public static void main(String[] args) {
System.out.println(TestEnum.findByKey(69)); // prints "SIXTY_NINE"
System.out.println(
TestEnum.values() == TestEnum.values()
); // prints "false"
}
}
You can now expect findByKey
to be a O(1)
operation.
References
- JLS 8.7 Static initializers
- JLS 8.9 Enums
Related questions
- Static initalizer in Java
- How to Initialise a static Map in Java
Note on values()
The second println
statement in the main
method is revealing: values()
returns a newly allocated array with every invokation! The original O(N)
solution could do a little better by only calling values()
once and caching the array, but that solution would still be O(N)
on average.
Although someone has suggested using Map<Integer, TestEnum>
think twice about it.
Your original solution, especially for small enums, may be magnitudes faster than using HashMap.
HashMap will probably be not faster until your enum contains at least 30 to 40 elements.
This is one case of "If it ain't broken, don't fix it".
Here is the most convenient way to find enum value by its field:
public enum TestEnum {
A("EXAMPLE_1", "Qwerty", 1),
B("EXAMPLE_2", "Asdfgh", 2),
C("EXAMPLE_3", "Zxcvbn", 3);
private final String code;
private final String name;
private final Integer typeID;
TestEnum(String code, String name, Integer typeID) {
this.code = code;
this.name = name;
this.key = typeID;
}
public String getCode() {
return code;
}
public String getName() {
return name;
}
public Integer getKey() {
return key;
}
public static TestEnum findValueByTypeId(Integer key) {
return Arrays.stream(TestEnum.values()).filter(v ->
v.getKey().equals(key)).findFirst().orElseThrow(() ->
new Exception(String.format("Unknown TestEnum.key: '%s'", key)));
}
}
You should have a HashMap with the numbers as keys and the enum values as values.
This map can typically be in your repository. Then you can easily replace an int variable from the database with your preferred enum value.
If your keys (int values) are stored in a database, then I will say its bad design to carry those keys around in an enum on your business layer. If that's the case, I will recommend not to store the int value in the enum.
One solution is to add
public final Test[] TESTS = { null, ONE, TWO, THREE };
public static Test getByNumber(int i) {
return TESTS[i];
}
To the enum.
If the internal data is not an integer, you could have a Map which you populate in a static { ... }
initializer. This map could later be used in the getByNumber
method above.
精彩评论