Reputation: 10981
With Java 8 I found a common way to get an enum from a value, it's using an Arrays.stream
with a filter on all the enum values, but recently, I came across another way to do it, with Stream.of
, what is the better way between each other and why? Is there another better way to do it?
Example:
public enum Foo {
BAR_1("Bar 1"),
BAR_2("Bar 2");
private String friendlyValue;
Foo(String friendlyValue){
this.friendlyValue = friendlyValue;
}
public String getFriendlyValue() {
return friendlyValue;
}
public static Foo fromFriendlyValue1(String friendlyValue){
return Stream.of(Foo.values()).filter(r -> r.getFriendlyValue().equals(friendlyValue)).findFirst().get();
}
public static Foo fromFriendlyValue2(String friendlyValue) {
return Arrays.stream(Foo.values()).filter(r -> r.getFriendlyValue().equals(friendlyValue)).findFirst().get();
}
}
Upvotes: 4
Views: 1703
Reputation: 3497
public enum Foo {
BAR_1("Bar 1"),
BAR_2("Bar 2");
private static class Holder {
static Map<String, Foo> map = new HashMap<String, Foo>()
{{
for(Foo f:Foo.values())
{
put(f.getFriendlyValue(),f);
}
}};
}
private String friendlyValue;
Foo(String friendlyValue){
this.friendlyValue = friendlyValue;
}
public String getFriendlyValue() {
return friendlyValue;
}
public static Foo fromFriendlyValue(String friendlyValue){
return Holder.map.get(friendlyValue);
}
}
This lazy initializes , unlike @bohemian's solution. And the magic here is an anonymous class extending hashmap, executing its anynymous constructor to loop all values of Foo into the map.
Although for most enums (which have a very limited amount of constants) , the simplest solution is just to loop them all.
public enum Foo {
BAR_1("Bar 1"),
BAR_2("Bar 2");
private String friendlyValue;
Foo(String friendlyValue){
this.friendlyValue = friendlyValue;
}
public String getFriendlyValue() {
return friendlyValue;
}
public static Foo fromFriendlyValue(String friendlyValue){
for(Foo f:Foo.values())
{
if(f.getFriendlyValue().equals(friendlyValue))
return f;
}
return null;
}
}
Since the cost of just doing the comparison is next to nothing for small enums.
Upvotes: -1
Reputation: 425033
The answer is neither. The cleanest, 1337 way is:
public enum Foo {
BAR_1("Bar 1"),
BAR_2("Bar 2");
private static class Holder {
static Map<String, Foo> map = new HashMap<String, Foo>();
}
private String friendlyValue;
Foo(String friendlyValue){
this.friendlyValue = friendlyValue;
Holder.map.put(friendlyValue, this);
}
public String getFriendlyValue() {
return friendlyValue;
}
public static Foo fromFriendlyValue(String friendlyValue){
return Holder.map.get(friendlyValue);
}
}
This implementation of fromFriendlyValue()
has O(1)
time complexity - ie it performs in constant time no matter how large the number of instances in your enum.
The kung fu here is the use of the Initialization-on-demand holder idiom, which neatly side-steps the problem of the initialization rules of an enum while maintaining encapsulation.
Upvotes: 0
Reputation: 3165
Stream.of is actually using Arrays.stream.
public static<T> Stream<T> of(T... values) {
return Arrays.stream(values);
}
So you can directly use Arrays.stream.
Upvotes: 7