using enum in switch/case - java

I have an entity that has an enum property:
// MyFile.java
public class MyFile {
private DownloadStatus downloadStatus;
// other properties, setters and getters
}
// DownloadStatus.java
public enum DownloadStatus {
NOT_DOWNLOADED(1),
DOWNLOAD_IN_PROGRESS(2),
DOWNLOADED(3);
private int value;
private DownloadStatus(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}
I want to save this entity in database and retrieve it. The problem is that I save the int value in database and I get int value! I can not use switch like below:
MyFile file = new MyFile();
int downloadStatus = ...
switch(downloadStatus) {
case NOT_DOWNLOADED:
file.setDownloadStatus(NOT_DOWNLOADED);
break;
// ...
}
What should I do?

You could provide a static method in your enum:
public static DownloadStatus getStatusFromInt(int status) {
//here return the appropriate enum constant
}
Then in your main code:
int downloadStatus = ...;
DowloadStatus status = DowloadStatus.getStatusFromInt(downloadStatus);
switch (status) {
case DowloadStatus.NOT_DOWNLOADED:
//etc.
}
The advantage of this vs. the ordinal approach, is that it will still work if your enum changes to something like:
public enum DownloadStatus {
NOT_DOWNLOADED(1),
DOWNLOAD_IN_PROGRESS(2),
DOWNLOADED(4); /// Ooops, database changed, it is not 3 any more
}
Note that the initial implementation of the getStatusFromInt might use the ordinal property, but that implementation detail is now enclosed in the enum class.

Every Java enum has an ordinal which is automatically assigned, so you don't need to manually specify the int (but be aware that ordinals start from 0, not 1).
Then, to get your enum from the ordinal, you can do:
int downloadStatus = ...
DownloadStatus ds = DownloadStatus.values()[downloadStatus];
... then you can do your switch using the enum ...
switch (ds)
{
case NOT_DOWNLOADED:
...
}

Related

Check if class has a variable in its constructor based on a string?

Let's say I have a class named Person and its constructor had variables like name, age, hairColor and so on. If I had a function that receives a string that should match one of the class's variables, how could I check if that class actually had that variable and how could I go about modifying it? For example:
public class Person {
public String name;
public int age;
public String hairColor;
public Person() {
name = "Bryce";
age = 21;
hairColor = "brown";
}
public void changeHairColor(String variable, String color) {
if (/*this class contains the variable passed as an argument to this method*/) {
// Person[variable] = color
}
}
}
I'm a python dev, mostly, so the method changeHairColor has some pseudo-python in it. I want to be able to edit the variable in a similar way you could edit variables inside of dictionaries with Python:
person = {
"name": "Bryce",
"age": 21,
"hairColor": "brown"
}
def changeHairColor(variable, color):
person[variable] = color
If that is at all possible.
The only way to do it in Java is to use Java Reflection API:
public class Test {
public String name;
public int age;
public String hairColor;
public void setProperty(String property, Object value) {
try {
Field declaredField = this.getClass().getDeclaredField(property);
switch (declaredField.getAnnotatedType().getType().getTypeName()) {
case "java.lang.String":
declaredField.set(this, value);
break;
// handle other types
}
} catch (NoSuchFieldException e) {
// handle exception
} catch (IllegalAccessException e) {
// handle exception
}
}
public static void main(String[] args) {
Test test = new Test();
test.setProperty("name", "Bob");
System.out.println(test.name);
}
}
I would not solve this with reflection. If your PlayerCharacter has an enumerable set of attributes, I would model these as a Java enum and store the attribute values within the PlayerCharacter object in an EnumMap:
import java.util.EnumMap;
public class PlayerCharacter {
public enum Attribute {
AGILITY,
DEXTERITY,
/* etc ...*/
VITALITY
}
private EnumMap<Attribute, Integer> attributes = new EnumMap<>(Attribute.class);
public PlayerCharacter() {
// initialize each attribute with a default value (0 in this example)
for (Attribute a : Attribute.values()) {
attributes.put(a, new Integer(0));
}
}
public int getValue(Attribute attribute) {
return attributes.get(attribute);
}
public void levelUp(Attribute attribute, int amount) {
attributes.put(attribute, attributes.get(attribute) + amount);
}
}
The biggest benefit of using an enum instead of plain old String (+reflection), is that this way you get compile-time type safety for the code that's using your PlayerCharacter.
Using Reflection API, you can access the methods and properties on an object at run time. The other answer describes its usage. But I don't recommend reflections for your problem. How about the following:
public void changeHairColor(String variable, String color) {
if("name".equalsIgnoreCase(variable))
this.name = color;
else if("age".equalsIgnoreCase(variable))
this.age = Integer.parseInt(color);
else if("color".equalsIgnoreCase(variable))
this.color = color;
else
throw new Exception ("error - property not available");
}
}
Note, your existing method name 'changeHairColor' doesn't make sense in the context. It should be someething like 'changeProperty' because you are not just changing the 'color', you are changing any available property with this method.

Can Java Enums shares some common codes among them?

I have two Enums as below
public enum Read {
PRIVATE (1), PUBLIC(2);
private final int value;
Read(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}
And
public enum Write {
CREATE (1), UPDATE(2);
private final int value;
Write(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}
Both enum needing some values to represent them. Is there a way for us to share the code, where the Read and Write "extends" from something that has value, instead of for every enum, I need to have getValue, value etc? Probably one way is to make a class, but thinking if we could make Enum "extensible"?
Don't fight it; embrace classes.
Enumerations generally represent some form of state; that is, each enum value has a specific business-associated state with it. You'd have to decide what Read.PRIVATE and Read.PUBLIC truly represented, but they're still states. The same is true of Write.CREATE and Write.UPDATE.
The real question now becomes, how do these two enums relate to one another? They likely don't, given that reading something is independent and severable from writing something.
In this instance, I'd probably represent it in a class:
public class Permission {
private Read readState;
private Write writeState;
public void setReadState(Read readState) {
this.readState = readState;
}
public void setWriteState(Write writeState) {
this.writeState = writeState;
}
}
It's unclear what the values would represent, since the enums are guaranteed unique, but take from this what you will.
You could use EnumSet to hold permissions like this:
Permission:
public enum Permission {
READ_PRIVATE, READ_PUBLIC, WRITE_CREATE, WRITE_UPDATE;
}
User:
public class User {
private final EnumSet<Permission> permissions;
public User(Permission... permissions) {
this.permissions = EnumSet.copyOf(Arrays.asList(permissions));
}
public boolean hasPermission(Permission permission) {
return permissions.contains(permission);
}
public void addPermisssion(Permission p) {
permissions.add(p);
}
public void removePermisssion(Permission p) {
permissions.remove(p);
}
}
Usage:
User user = new User(Permission.READ_PRIVATE, Permission.WRITE_UPDATE);
if ( user.hasPermission(Permission.WRITE_UPDATE) )
{
//do something...
}

How to set required constants for methods?

I am creating a method called setState and I want to use binary operators for it, but I want to create something to check if the passed argument is a constant defined in the class:
public static final int STATE1 = 0b1;
public static final int STATE2 = 0b10;
public static final int STATE3 = 0b100;
public void setState(int stateType, boolean state){
if(state){
this.state |= stateType;
}else{
this.state &= ~stateType;
}
}
So when I type setState(10, false) it will say: Wrong argument type, found x, required y
you only want stateType to be one of STATE1, STATE2, or STATE3?
You could use an enum defined in that class. Something like:
public class MyClass{
public enum State{
STATE1 (0b1),
STATE2(0b10),
STATE3(0b100);
public final int value;
State(int value){
this.value = value;
}
}
public void setState(State stateType, boolean state){
if(state){
this.state |= stateType.value;
}else{
this.state &= ~stateType.value;
}
}
}
One way to check a value against a group of allowed values is a Set<Integer> that contains all the allowed values. You can construct such set in a static constructor of the class, i.e.
private static final Set<Integer> allowedState = new HashSet<Integer>();
static {
allowedState.add(STATE1);
allowedState.add(STATE2);
allowedState.add(STATE3);
}
Now you can check if the state passed to you is valid by verifying that allowedState contains stateType:
if (!allowedState.contains(stateType)) {
// Throw an exception
}
To ensure that the allowedState set is immutable use Collcetions.unmodifiableSet(). Modifier final only ensures that the reference cannot be redinded to another object.
However, an approach based on raw int constants is not idiomatic to Java. A better way to achieve the same effect would be wrapping the states in an enum (tutorial), which would make sure that only a valid constant could be passed to your setState method:
public enum State {
STATE1(0b1)
, STATE2(0b10)
, STATE3(0b100);
private final int bitMask;
State(int bitMask) { this.bitMask = bitMask; }
public int getBitMask() { return bitMask; }
}

Tuple Enum in Java

I'm very new in Java and were wondering and didn't find anything about it.
Can you create enum tuple ?
public enum Status {OPEN : "1", CLOSED: "2", DELETED: "3"}
I will need to access both "OPEN" or "1"
You could always create a custom constructor for your enum..
public enum Status {
OPEN("1"),
CLOSED("2"),
DELETED("3");
private String code;
public Status(String code) {
this.code = code;
}
public String getCode() {
return code;
}
}
Then you can access with Status.OPEN.getCode(). This functions as an effective mapping between an enum type and a code value.
You can do something like this:-
public enum Currency {PENNY(1), NICKLE(5), DIME(10), QUARTER(25)};
But for this to work you need to define a member variable and a constructor because PENNY (1) is actually calling a constructor which accepts int value , see below example.
public enum Currency {
PENNY(1), NICKLE(5), DIME(10), QUARTER(25);
private int value;
private Currency(int value) {
this.value = value;
}
};
Constructor of enum in java must be private any other access modifier will result in compilation error. Now to get the value associated with each coin you can define a public getValue() method inside java enum like any normal java class. Also semi colon in the first line is optional.
private int getValue() { return value; }
and get values like this:-
PENNY.getValue(); //returns int 1
Refrence:
Solution by #christopher cover only first part. Creating ENUM.
You will need one more method that match code with enum value:
public static Status byCode(String code){
for(Status s : Status.values()) {
if (s.code.equals(code)) {
return s;
}
}
throw new IllegalArgumentException("Code does not match");
}
now you can get enum value by name and by code.

Java enums and Objective-C enums

I have the following enum in Objective-C:
typedef enum {
APIErrorOne = 1,
APIErrorTwo,
APIErrorThree,
APIErrorFour
} APIErrorCode;
I use the indexes to reference an enum from an xml, for example, xml may have error = 2, which maps to APIErrorTwo
My flow is I get an integer from the xml, and run a switch statement as follows:
int errorCode = 3
switch(errorCode){
case APIErrorOne:
//
break;
[...]
}
Seems Java dislikes this kind of enum in a switch statement:
In Java it seems you can't assign indexes to enum members. How can I get a Java equivalent of the above ?
Java enums have a built-in ordinal, which is 0 for the first enum member, 1 for the second, etc.
But enums are classes in Java so you may also assign them a field:
enum APIErrorCode {
APIErrorOne(1),
APIErrorTwo(27),
APIErrorThree(42),
APIErrorFour(54);
private int code;
private APIErrorCode(int code) {
this.code = code;
}
public int getCode() {
return this.code;
}
}
One question per post is the general rule here.
But evolving the JB Nizer answer.
public enum APIErrorCode {
APIErrorOne(1),
APIErrorTwo(27),
APIErrorThree(42),
APIErrorFour(54);
private final int code;
private APIErrorCode(int code) {
this.code = code;
}
public int getCode() {
return this.code;
}
public static APIErrorCode getAPIErrorCodeByCode(int error) {
if(Util.errorMap.containsKey(error)) {
return Util.errorMap.get(error);
}
//Or create some default code
throw new IllegalStateException("Error code not found, code:" + error);
}
//We need a inner class because enum are initialized even before static block
private static class Util {
private static final Map<Integer,APIErrorCode> errorMap = new HashMap<Integer,APIErrorCode>();
static {
for(APIErrorCode code : APIErrorCode.values()){
errorMap.put(code.getCode(), code);
}
}
}
}
Then in your code you can write
int errorCode = 3
switch(APIErrorCode.getAPIErrorCodeByCode(errorCode){
case APIErrorOne:
//
break;
[...]
}

Categories