Reputation: 2421
I'd like to create a few enums such as described in this answer: Lookup enum by string value
(I.e an enum that has a toString() and a name which is different to the enum itself)
Is there any way I can reuse this functionality without having to reimplement it in each enum?
Upvotes: 1
Views: 159
Reputation: 147154
If you pass in the list of possible values, then you can do it without so much as depending upon the type being an enum
.
public static <T> T findByString(T[] values, String toString) {
Objects.requireNonNull(toString);
for (T t : values) {
if (toString.equals(t.toString())) {
return t;
}
}
throw new IllegalArgumentException();
}
Call with:
Blah blah = SomeClass.findByString(Blah.values(), str);
Rather than calling Blah.values()
every time, you could use put it in an object, which could be passed around and used generically. Perhaps other methods added later.
public interface ByString<T> { // Choose a better name.
T find(String toString);
}
[...]
private static final ByString<Blah> blahs = byString(Blah.values());
[...]
public static <T> ByString<T> byString(T[] values) {
final T[] valuesCopy = values.clone();
return new ByString<T>() {
public T find(String toString) {
return SomeClass.findByString(valuesCopy, toString);
}
};
}
[...]
Call with:
Blah blah = blahs.find(str);
In fact, you might want to optimise that. Do the toString
ing once, and use a map.
public static <T> ByString<T> byString(T[] values) {
final Map<String,T> byToStrings = new HashMap<>(
(int)(values.length/0.75f)+1 // Doesn't HashMap construction suck.
);
for (T value : values) {
byToStrings.put(values.toString(), value);
}
return new ByString<T>() {
public T find(String toString) {
T value = byToStrings.get(toString);
if (value == null) {
throw new IllegalArgumentException();
}
return value;
}
};
}
Upvotes: 3
Reputation: 533492
If you have many enums which share the same functionality I would either.
Java 8 will make this simpler with virtual extensions. It will allow you to define a default implementation on the interface (which has to be a helper/static method)
Upvotes: 1
Reputation: 1500365
I don't believe you can get away from the "adding a field and a property" in each enum. You can make your fromText
method delegate to a common method though, if you create an interface for that property, and pass either values()
or (better) an EnumSet
. (Better: write a method to create a case-insensitive Map
, and call that once in each enum, storing the result in a static variable.)
Upvotes: 3