Using Enum as a int value - java

Am trying to use Enum as Constants for readability as below .
Public enum x { test1 , test2 , test3 }
I want to pass this enum into a method and use it as a int value as shown
private void (int type)
{
switch(int)
{
case enum.X:
// do somthing
break;
}
} ;
Can we use enum here as its more clearer than using a int value .( like switch 1 etc) . Is it possible to use this way.?

Yes, you should be able to use an enum in a switch statement in Java:
public enum SomeEnum { FOO, BAR, BAZ };
// in a class...
private void something(SomeEnum s) {
switch (s) {
case FOO:
// do something
break;
case BAR:
// do something else
break;
}
}
Not sure I understand how int values tie into this, but you can have fields/methods on an enum like in a normal Java class, and can use these to hold int (or any other type) values as on any other POJO.
Here's an example in which we declare a constructor for an enum class, so that you can pass in values for internal variables at the time each instance of the enum is constructed. To help you follow what's going on: First we declare the items in the enum - each declaration invokes the constructor, so we can pass in instance variables here. Then the code for the enum class follows, as with a normal Java class.
public enum AnotherEnum {
ONE(1, "un"), TWO(2, "deux"), THREE(3, "trois"), FIFTY_SEVEN(57, "cinquante-sept");
private final int someInt;
private final String french;
private AnotherEnum(int i, String s) {
this.someInt = i;
this.french = s;
}
public int getSomeInt() {
return this.someInt;
}
public String getFrench() {
return this.french;
}
}
So for example, System.out.println(AnotherEnum.TWO.getSomeInt()) would print 2, and System.out.println(AnotherEnum.FIFTY_SEVEN.getFrench()) would print cinquante-sept.

No, you cannot say:
case Enumerator.ordinal():
But you could say:
switch(EnumObject.values()[intVar]) {
case Enumerator1:
...
}

Another way you can do this by doing a little more work with you enum class.
public enum Foo {
X (1),
Y (2);
private int value;
Foo (int value)
{
this.value = value;
}
}
Now all you need to do is:
switch (int)
{
case Foo.X: doSomething ();break;
case Foo.Y: doSomething ();break;
}

Related

Switch String with Enum variables

I have got an Enum with different values and want to switch a string variable. Now I hit a wall trying to convert the Enum values to Strings, that I can use as case constant.
My best try was to convert the Enum to a String array, but the switch doesn't seem to accept array values as a case constant. (IntelliJ says: "constant expression required")
Enum myEnum = {FOO, BAR}
String input = "foo"
final String[] constant = Arrays.stream(myEnum.values()).map(Enum::name).toArray(String[]::new);
//converts Enum to String[]; made it final, so it is "constant"
switch (input) {
case constant[0]:
System.out.println("foo");
break;
case constant[1]:
System.out.println("bar");
break;
}
Is there an elegant way to make this switch depend on the Enum?
You shouldn't convert it because it isn't needed. Also, your code won't even compile because case is a reserved keyword in Java.
You should take a look at the valueOf method of an Enum.
Your code can look like that:
public enum MyEnum {FOO, BAR}
//method
String input = "foo";
MyEnum niceFound = MyEnum.valueOf(input.toUpperCase());
That will return FOO but can throw an IllegalArgumentException when the given value isn't present as type.
You can do this :
public enum MyEnum {
FOO("foo"),
BAR("bar");
private String value;
public String getValue() {
return value;
}
public static MyEnum getState(String value) {
switch (value) {
case "foo":
return FOO;
case "bar":
return BAR;
}
return null;
}
private MyEnum(String value) {
this.value = value;
}
}
Now, in your class, you can :
MyEnum myEnum = getState("foo"); // returns MyEnum.FOO
Also make sure you handle the case when getState() returns null
A solution with Java 8+ streams would be to create a method inside your enum :
public static Optional<MyEnum> getByValue(final String value) {
return Arrays.stream(MyEnum.values())
.filter(myEnum -> myEnum.value.equals(value))
.findFirst();
}
This returns optional in case there is no enum value for your String parameter. But you can change it according to your needs.
Use MyEnum.valueOf(value.toUpperCase())
public enum MyEnum {
FOO, BAR;
}
public static void process(String value) {
try {
switch (MyEnum.valueOf(value.toUpperCase())) {
case FOO :
System.out.println("FOO");
break;
case BAR :
System.out.println("BAR");
break;
default :
break;
}
}
catch (IllegalArgumentException e) {
// TODO: handle exception
}
public static void main(String[] a){
process("foo");
}

Is there any way to pass a variable while initializing an enum instead of passing actual value in java?

I need to pass a class variable to an enum while initializing it .But the class variable is not accessible while initializing the enum . So how can this be achieved ?
I tried passing variable of another class, same class where the enum resides . Both didn't work.
public class ComponentConstants {
public Constants constants = Constants.getInstance();
enum FIELDS_RESOURCES {
//instead of text i want to use constants.data_type.text. But I was not able to.
SourcetType(true, "text", "Source Type", "source_type", 255, false); //No I18N
private VOCFIELDS_RESOURCES(boolean isCustomField, String data_type, String field_label, String api_name, int length, boolean isVisible) {
this.isCustomField = isCustomField;
this.data_type = data_type;
this.field_label = field_label;
this.api_name = api_name;
this.length = length;
this.isVisible = isVisible;
}
}
}
In the above I want to use the value from constants since if there is any change there ,it should be reflected in my code too . Single point of constants , but i was not able to use it. How can this be achieved and why is it not allowing to use other variables? Thanks!
public class Main {
public enum Enumeration {
Test(Constants.a, Constants.b); // can refer to constant "a" & "b" static variables
private final String a;
private final String b;
Enumeration(String a, String b) {
this.a = a;
this.b = b;
}
}
public static class Constants {
static String a = "a";
static String b = "b";
}
}
If you utilize static fields as constants, they can be referenced within enumeration constructors. More details here regarding enum fields.

Why JNI can't find self-define static in enum?

i define a enum like below:
public enum EventType {
UPDATE(0), ADD(1), REMOVE(2), RESPONSE(3);
private Integer id;
public Integer id() {
return this.id();
}
/**
* constructor method
*/
EventType(Integer id) {
this.id = id;
}
public static EventType getInstance(Integer id) {
switch (id) {
case 0:
return UPDATE;
case 1:
return ADD;
case 2:
return REMOVE;
case 3:
return RESPONSE;
default:
return null;
}
}
}
I want to create a enum instance by callback getInstance method, the JNI code like below:
jclass eventType_cls = (*env)->FindClass(env,"com/example/hellojni/EventType");
jmethodID midInstance = (*env)->GetStaticMethodID(env,eventType_cls,"getInstance","(I)[Lcom/example/hellojni/EventType;");
it pass the compiler, but when run to the JNI GetStaticMethodID method, the platform throws a error like below:
java.lang.NoSuchMethodError: no static method with name='getInstance'
signature='(I)Lcom/example/hellojni/EventType;'
in class Lcom/example/hellojni/EventType;
I don't know what's different enum with other class, do you have any idea?
The signature that you use in JNI for the method is looking for a method that looks like this:
public static EventType[] getInstance(int id) {
}
So the return type of the signature is definitely wrong. It should not have the [ there.
Now you have two possibilities either change the input type to int on the Java side or you change the type signature to (Ljava/lang/Integer;)Lcom/example/hellojni/EventType;.
Now you will realize that the second alternative is not very easy to handle since to access the value of the Integer you would have to use JNI methods and all the other fuzz.
You should also rethink why you would ever want to use the Integer wrapper instead of the primitive int in you Java code. There is simply no reason for it.
Rewrite your enum to something look like this:
public enum EventType {
UPDATE(0), ADD(1), REMOVE(2), RESPONSE(3);
private int id;
public int id() {
return this.id();
}
/**
* constructor method
*/
EventType(int id) {
this.id = id;
}
public static EventType getInstance(int id) {
switch (id) {
case 0:
return UPDATE;
case 1:
return ADD;
case 2:
return REMOVE;
case 3:
return RESPONSE;
default:
return null;
}
}
}
And change the JNI method lookup to this:
jmethodID midInstance = (*env)->GetStaticMethodID(env,eventType_cls,"getInstance","(I)Lcom/example/hellojni/EventType;");

In Java, how to iterate on the constants of an interface?

in an interface, I store constants in this way (I'd like to know what you think of this practice). This is just a dummy example.
interface HttpConstants {
/** 2XX: generally "OK" */
public static final int HTTP_OK = 200;
public static final int HTTP_CREATED = 201;
public static final int HTTP_ACCEPTED = 202;
public static final int HTTP_NOT_AUTHORITATIVE = 203;
public static final int HTTP_NO_CONTENT = 204;
public static final int HTTP_RESET = 205;
public static final int HTTP_PARTIAL = 206;
...
}
Is there a way I can iterate over all constants declared in this interface ?
Using reflection:
Field[] interfaceFields=HttpConstants.class.getFields();
for(Field f:interfaceFields) {
//do something
}
But anyway, if you can redesign your class, I would recomend you to handle a static enum constants construction. So, suposing your class will contain always an int value for every constant:
enum HttpConstants {
HTTP_OK(200), HTTP_CREATED(201), HTTP_ACCEPTED(202),
HTTP_NOT_AUTHORITATIVE(203),HTTP_NO_CONTENT(204),
HTTP_RESET(205), HTTP_PARTIAL(206) /* ... */;
private int value;
HttpConstants(int aValue) {
value=aValue;
}
public int getValue() {
return value;
}
}
Then, to loop on it:
for(HttpConstants val: HttpConstants.values()) {
int value=val.getValue();
//...
}
Thus, avoiding the access to the reflection API.
I would create these constants as an enumeration. Enums in Java can have their own fields and methods, which very convenient for your case. So I would do this the following way:
enum HttpConstant {
HTTP_OK(200),
HTTP_CREATED(201),
HTTP_ACCEPTED(202),
HTTP_NOT_AUTHORITATIVE(203),
HTTP_NO_CONTENT(204),
HTTP_RESET(205),
HTTP_PARTIAL(206);
private final int id;
HttpConstant(int id) {
this.id = id;
}
int getId() {
return id;
}
}
Now the iteration is easy:
for (HttpConstant constant : HttpConstant.values()) {
//Do something with the constant
}
This way it is also easy to add associate some new values with the constants, you just have to add new fields.
Right now you may use reflection:
Field[] interfaceFields = HttpConstants.class.getFields();
for (Field field : interfaceFields) {
int constant = field.getInt(null);
//Do something with the field
}
However, it is better to use the approach with enums because with reflection coding errors result in runtime exceptions instead of compile-time errors.
for(Field f : HttpConstants.class.getFields()){
int constant = f.getInt(null);
}
public enum HttpConstant {
/** 2XX: generally "OK" */
HTTP_OK(200).
HTTP_CREATED(201),
HTTP_ACCEPTED(202),
HTTP_NOT_AUTHORITATIVE(203),
HTTP_NO_CONTENT(204),
HTTP_RESET(205),
HTTP_PARTIAL(206);
private int code;
private HttpConstant(int code) {
this.code = code;
}
public int getCode() {
return code;
}
}
with HttpConstant.values().
Well usually when i have something like that i make a Map in the interface that has the keys - constant names with values constant - values.
And that's how i can iterate over them.
I'd like to know what you think of this practice
Consider using an enum instead of an interface with constants.
enum HttpResultCode {
HTTP_OK(200),
HTTP_CREATED(201),
HTTP_ACCEPTED(202),
HTTP_NOT_AUTHORITATIVE(203),
HTTP_NO_CONTENT(204),
HTTP_RESET(205),
HTTP_PARTIAL(206);
private final int code;
private HttpResultCode(int code) {
this.code = code;
}
public int getCode(int code) {
return code;
}
public static HttpResultCode forCode(int code) {
for (HttpResultCode e : HttpResultCode.values()) {
if (e.code == code) {
return e;
}
}
throw new IllegalArgumentException("Invalid code: " + code);
}
}

Get enum by its inner field

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 testEnum;
}
}
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.

Categories

Resources