Get enum values from Enum object - java

If I were to declare an enum like so
public enum Foo {A, B, C}
then I can get the enum values using
Foo[] values = Foo.values();
However if I wanted to pass Foo as a generic type, like so, I can't get the values since it's generic.
class Bar<E extends Enum<E>> {
public Bar(E e) {
E[] values = e.values(); // not possible
}
}
Is it possible to iterate over the enum values any other way?

You'll have to pass the Class object:
public Bar(Class<E> clazz) {
E[] values = clazz.getEnumConstants();
}
...or, if you have one element e of the enum, you might be able to use e.getDeclaringClass().getEnumConstants(). (Don't use e.getClass().getEnumConstants(), which won't work if your enum constants define their own constant-specific methods.)
Another option: EnumSet.allOf(clazz), which is actually more efficient than clazz.getEnumConstants() in many ways, since it's O(1) and not O(n) in the number of enum constants.

Related

How to return the same generic Collection-type with different element-type?

I have a method, that maps elements of a collection to other object and returns a collection containing the mapped elements. I want the returned Collection to be of the same Collection-type as the input Collection, but with a different element type.
My method would look something like this:
<E extends OriginalElement, T extends TargetElement,
C extends Collection<E>, R extends C<T>> R map(C elementsToMap) {
// snip
}
Obviously the part R extends C<T> doesn't work.
How can I specify that return type to be the same subclass of Collection as Type C, but with element type T instead of E?
You can't, I don't think, because e.g. ArrayList<String> and ArrayList<Integer> are essentially unrelated types.
Plus, when you say "same generic Collection-type", do you mean:
"if I give you some subclass of ArrayList, you'll give me back an instance of java.util.ArrayList"; or
"if I give you a specific subclass of ArrayList, you'll give me back an instance of the same specific subclass of ArrayList"?
Not only is that hard, because in general you don't know how to instantiate arbitrary subclasses, you might not be able to create such an instance, for example if the input is an IntegerArrayList (extends ArrayList<Integer>), and you want to map the elements to Strings. So, whilst you could return a java.util.ArrayList<String> in that case, you can't have a generic solution because you need some knowledge of "which type to instantiate in this specific case".
I am going to make an unquantified assertion that a small handful of collection types can handle most cases. So, provide overloads for these specific types:
</* type variables */> ArrayList<T> map(ArrayList<E> input) { ... }
</* type variables */> HashSet<T> map(HashSet<E> input) { ... }
</* type variables */> ImmutableList<T> map(ImmutableList<E> input) { ... }
// etc.
and then provide a general method for the other cases, and leave it up to callers to specify the collection type they want:
</* type variables */> Stream<T> map(Collection<E> input) { ... }
and then call the general method from the specific methods:
</* type variables */> ArrayList<T> map(ArrayList<E> input) {
return map((Collection<E>) input).collect(toCollection(ArrayList::new));
}
// etc.

Java: How to get Values of an Enum Class from an Generic Type Object instance?

I want to create an Enum editor, which takes an Enum type as its generic.
E is a generic type, but restricted to be an Enum type. How can I get the values of the Enum class from the instance e?
public class ComboBoxEnumEditor<E extends Enum<E>>{
public ComboBoxEnumEditor(E e) {
// how to get values of E from e?
// attemp1:
List values = e.getClass().values();
// attemp2:
List values = ((Enum.class)e.getClass()).values();
// attemp3:
List values = ((Enum.class)e.getClass()).values();
// none of the above works...
}
}
Say I have an Enum
public enum Location {
Default( false, EAttributeLocation.MAIN_TABLE_IF_AVAILABLE ),
Main( false, EAttributeLocation.MAIN_TABLE ),
Overflow( false, EAttributeLocation.OVERFLOW_TABLE ),
Separate( false, EAttributeLocation.SEPARATE_TABLE );
......
}
I want my ComboBoxEnumEditor be able to do
{
ComboBoxEnumEditor(new Location());
}
Please help, thanks.
It looks like you are looking for (but I may be mistaken)
Enum[] values = e.getClass().getEnumConstants();
or as mentioned by #pbabcdefp in this answer (big +1 for him) if you would like to have E[] instead of Enum[]
E[] values = e.getDeclaringClass().getEnumConstants();
Also based on
...which takes an Enum Class as its generic
your argument should probably be Class<E> clazz not E e itself so you could use it with ComboBoxEnumEditor(Location.class);. In that case you could simply use
E[] values = clazz.getEnumConstants();
E[] arr = e.getDeclaringClass().getEnumConstants();
Short answer... You can't. Doing this is not valid syntax since you can't instantiate an enum:
ComboBoxEnumEditor(new Location());
Instead, you need to pass the class of your enum and change your method signature for that, e.g.
ComboBoxEnumEditor(Location.class);

Is there a way to get the enum type from and ordinal value?

What i mean by that is suppose
Enum xyzType {
A,
B,
C,
D
}
I know I can get the ordinal a value of C, by doing xyzType.C.ordinal() which is 2.
Suppose I just have 2, I would to get the enum type C. I can't seem to find anything in the enum API that would do this. I would prefer not to have a huge switch statement to compare each ordinal value and return the enum. Is there a better to do this ?
The simplest approach is:
xyzType xyz = xyzType.values()[ordinalValue];
However, this will create a new array each time. An alternative would be to cache it within the enum:
public enum Xyz {
Foo, Bar;
private static final Xyz[] VALUES = values();
public Xyz fromOrdinal(int ordinal) {
return VALUES[ordinal];
}
}

How to cast a value from one enum to another in Java?

How can I cast a value from Enum1 to Enum 2 in Java?
Here is an example of what I'm trying to do :
public enum Enum1 {
ONE,
TWO,
THREE;
}
public enum Enum2 {
FOUR,
FIVE,
SIX;
}
So I want to do something like this:
Enum2 en2 = (Enum2)ONE;
Is it possible and how can I do that?
Thanks in advance!
You cannot cast from one enum to another, however each enum has guaranteed order, and you can easily translate one enum to another (preserving order). For example:
enum E1 {
ONE, TWO, THREE,
}
enum E2 {
ALPHA, BETA, GAMMA,
}
we can translate E1.TWO to/from E2.BETA by:
static E2 E1toE2(E1 value) {
return E2.values()[value.ordinal()];
}
static E1 E2toE1(E2 value) {
return E1.values()[value.ordinal()];
}
The answer depends on what the "casting" should do...
Casting by ordinal position
In the provided example, there is no commonality between the two sets of enum values so I'm assuming the intention was to translate by ordinal position so Enum1.ONE => Enum2.FOUR, Enum1.TWO => Enum2.FIVE and Enum1.THREE => Enum2.SIX. This can be done as follows:
Enum2 en2 = Enum2.values()[Enum1.ONE.ordinal()];
A natural follow-on question is how this can be extended to a generic function that does the same for any two enum types. Not for the faint hearted but this does the job - it requires the Google Guava library:
public <F extends Enum<F>> F castByOrdinal(Enum<?> e, Class<F> fClass) {
return Iterators.get(EnumSet.allOf(fClass).iterator(), e.ordinal());
}
If Guava isn't being used, it can be done manually in a few more lines of code:
public <F extends Enum<F>> F castByOrdinal(final Enum<?> e, final Class<F> fClass){
final Iterator<F> iter = EnumSet.allOf(fClass).iterator();
int count = 0;
F fValue = null;
while (count <= e.ordinal()) {
if (!iter.hasNext()) {
return null; // ...Or throw an exception e.g. IndexOutOfBoundsException
}
fValue = iter.next();
count++;
}
return fValue;
}
Example usage:
Enum2 en2 = castByOrdinal(Enum1.ONE, Enum2.class);
Casting by shared enum value names
There is another possible way of casting between enums that share some of the same value names.
E.g:
enum Shape {
TRIANGLE, SQUARE, PENTAGON, HEXAGON, UNKNOWN, NOT_APPLICABLE
}
enum Size {
SMALL, MEDIUM, LARGE, UNKNOWN, NOT_APPLICABLE
}
The casting will only work for common values (i.e. UNKNOWN and NOT_APPLICABLE above) and can be done as follows:
Size size = Size.valueOf(Shape.UNKNOWN.name());
This will throw an IllegalArgumentException if the value name does not exist in the target enum. The generic method for this casting is a bit simpler:
public <F extends Enum<F>> F castByName(final Enum<?> e, final Class<F> fClass) {
return F.valueOf(fClass, e.name());
}
Example usage:
Size size = castByName(Shape.UNKNOWN, Size.class);
You can define a method in Enum1 to return the corresponding Enum2:
enum Enum1 {
ONE {
#Override
public Enum2 toEnum2() {
return Enum2.ALFA;
}
},
TWO {
#Override
public Enum2 toEnum2() {
return Enum2.BETA;
}
}
,
THREE {
#Override
public Enum2 toEnum2() {
return Enum2.GAMMA;
}
}
;
public abstract Enum2 toEnum2();
}
enum Enum2 {
ALFA, BETA, GAMMA;
}
or, a bit more readable (IMO):
enum Enum1 {
ONE(Enum2.ALFA),
TWO(Enum2.BETA),
THREE(Enum2.GAMMA);
private final Enum2 enum2;
private Enum1(Enum2 enum2) {
this.enum2 = enum2;
}
public Enum2 toEnum2() {
return enum2;
}
}
enum Enum2 {
ALFA, BETA, GAMMA;
}
EDIT:
if you need to maintain the 2 enums decoupled, create a map containing the mapping from Enum1 to Enum2 (in a 3rd utility class).
It's not possible. Enum1 and Enum2 are different types with nothing in common.
Even though this ticket was active quite a while ago I'm adding another possibility:
You could also create a Map e.g. like this:
HashMap<Enum1, Enum2> e1ToE2 = new HashMap<Enum1, Enum2>();
e1ToE2.put(Enum1.ONE, Enum2.FOUR);
e1ToE2.put(Enum1.TWO, Enum2.FIVE);
usage
Enum2 e2 = e1ToE2.get(Enum1.ONE);
(+) you dont have to double check the order of your elements
(+) easy to read
(+) fast
(-) requires space
Correct me if I'm wrong :)
You can't do that, because they're objects of different classes.
You could convert from one to the other based on ordinal value or name, but I'd question the design of any program that needed to do that.
You can't ; but you can create a static method in your enums, with a translation code. But you must have a clear idea of the rules you want to implement.
A cast operation is not possible, but you can write a static member function for enum1 that casts enum2 to enum1:
public static Enum1 fromEnum2(Enum2 enum2) {
...
}
By the way, you can assign an ID to every constant of both enums which simplifies the implementation.
Here is a tutorial on enums.
It probably won't help you, but you can have
public enum Enum1 implements MyInterface {...}
public enum Enum2 implements MyInterface {...}
We don't have enough information about what you are trying to do to help you.
It makes no sense as it is to cast an enum to another enum.
You cannot cast from one enum to another, however each enum has guaranteed order, and you can easily translate one enum to another

Is it possible to iterate through several enum classes?

I have three enum classes. I want to somehow put these in an array, loop through the array and call the same method in each enum class. Is this possible in Java?
It seems to me you can't place enum types in an array structure (unless i've missed how).
Thank you.
Let each enum type implement a common interface that has the common method that you want into invoke. You can now cast each enum, while iterating, to this common interface and call the method. Also look at EnumSet
Here is an example with 2 enums and using reflection:
enum Colour{
RED,
BLUE,
GREEN;
public void foo(){
System.out.println("COLOUR");
}
}
enum Fruit {
APPLE,
BANANA,
PEAR;
public void foo(){
System.out.println("FRUIT");
}
}
You can put the classes into an array and use reflection to call a method for each enum constant:
//create an array
Class[] arr = new Class[2];
arr[0] = Colour.class;
arr[1] = Fruit.class;
//call the foo method
for(Class c : arr){
Method m = c.getMethod("foo", null);
for(Object o : c.getEnumConstants()){
System.out.println("Invoking foo on:" + o);
m.invoke(o, null);
}
}
If, by enum classes, you mean three different enums, each with their own elements, then you can use an array of type Enum[]. If you mean three items from a single enum, let's call it enum X, then you would put them in an array of type X[].
If you are trying to call a standard Enum function on each one, then you should be all set. If you need to call your own function on them, and are going with an array of Enum[], you'll either need to use reflection or have them all implement the same interface.

Categories