Enum with customized values and Default value - java

How to retrieve the enum name using value. By passing JOHN I need to retrieve the value as single
public enum Status {
JOHN("single"),
ALEX("married"),
MARTHA("not known");
}
Is it possible to have default value as well in-case value does not match?

To do this you need to define a constructor and a String variable. Then you could create a getter method to return the String variable:
public enum Status {
JOHN("single"),
ALEX("married"),
MARTHA("not known");
private String value;
private Status(String str) {
value = str;
}
public String getValue() {
return this.value;
}
}
And then to get the value you can do:
Status.JOHN.getValue()
To get the enum from a String you can use the valueOf() method:
Status.valueOf("JOHN").getValue();
However this will throw an error if the inputted String does not correspond to an enum. You could either wrap it in a try-catch to assign a default to it:
try {
Status.valueOf("JOHN").getValue();
} catch(IllegalArgumentException e) {
//Assign default
}
However a better design might be to put the possibilities into a HashMap and see if the inputted String is in the HashMap:
Map<String, Status> status = new HashMap<>();
status.put("JOHN", Y.JOHN);
if(status.containsKey(input)) {
//Do stuff
} else {
//Assign default
}

Define your enum like
enum Status {
JOHN("single"), ALEX("married"), MARTHA("not known");
private String value;
private Status(String value) {
this.value = value;
}
public String getValue() {
return value;
}
}
Now to fetch the value :
System.out.println(Status.JOHN.getValue());
Here define a parameterized constructor for each enum and store this value in a member variable.

A Java enum is an object, just like other objects in most ways. You can give it fields, methods, and constructors.
In this case, you can provide a marriage field and set it in a constructor just like you would for any other object.
Check out the official page on Java enums to see official examples, specifically the example with planets for your case. The Java Tutorials: Enum Types
Note also that you might not want to represent this specific data as an enum. You will be limited to only those 3 specific people by doing so. This is only appropriate if you know that you definitely will have only this specific list of people for the entire lifetime of this code. Otherwise you should just use a normal object.
A better idea might be to have a marriage enum and give your people a field of that type.
public enum MarriageStatus
{
Married,
NotMarried,
Unknown;
}
public class Person
{
String name = "Unknown";
MarriageStatus marriageStatus = MarriageStatus.Unknown;
}

Related

How to access constants from a java class through other variable?

I have java class which has all constants as given below:
public final class CategoryIDs {
public static final String Extraction_of_natural_gas = "1111";
public static final String Mining_of_hard_coal = "2222";
public static final String Mining_of_iron_ores = "3333";
public static final String Mining_of_lignite = "4444";
}
Now I want to access these constants in some other class through a variable which holds name of the variable.
For example:
String temp = "Extraction_of_natural_gas";
Using this temp variable I want to access constants from above class. But I can't do CategoryIDs.temp as it isn't allowed. So what is the best way to achieve this?
You can use reflection to extract it:
String value = (String) CategoryIDs.class.getField(temp).get(null);
The null argument passed to get signifies this is a static field, and no instance is required in order to get its value.
Note that this technique is very error prone. The code above doesn't contain any error checking or exception handling in order to make it easier to read, but a real application should probably contain them.
If you really, really need to do this with your current structure, you could use reflection.
However, you may well find that an enum would be a better fit. Something like:
public enum CategoryID {
EXTRACTION_OF_NATURAL_GAS("Extraction_of_natural_gas", 1111),
MINING_OF_HARD_COAL("Mining_of_hard_coal", 2222),
MINING_OF_IRON_ORES("Mining_of_iron_ores", 3333),
MINING_OF_LIGNITE("Mining_of_lignite", 4444);
private static final Map<String, CategoryID> keyMap;
static {
keyMap = new HashMap<>();
for (CategoryID category : CategoryID.values()) {
keyMap.put(category.getKey(), category);
}
}
private final String key;
private final int value;
public int getValue() {
return value;
}
public String getKey() {
return key;
}
private CategoryID(String key, int value) {
this.key = key;
this.value = value;
}
public static CategoryID fromKey(String key) {
return keyMap.get(key);
}
}
Benefits of this approach:
You separate the name in the code (which is now more conventional for Java) from the key you'd provide in the data. That means you can use whatever keys you'd like in the data, including ones with spaces in etc. They no longer need to be valid identifiers.
You still get compile-time safety when you refer to the enum values from code.
You get better safety as you'll never accidentally use a string instead of a category ID, which you could easily have done using your constants.
I think you are looking for introspection. This is the "read only" part of reflection, in which you can retrieve the value of an object.
The code would be as follows, pieced for ease of understanding:
Object value = null;
String constName = "Bar";
Field constant = Foo.class.getField( constName );
if ( constant != null ) {
value = constant.get( null );
}
if ( value != null ) {
System.out.println( value );
} else {
System.out.println( "Constant " + constName + " was not found." );
}
Interestingly, you can access the value from the Field object calling get(), and you pass null because the constant is static, and thus you don't have an instance to extract the value from.
You can find the whole code here: http://ideone.com/v4fcvH
Hope this helps.

associating int value to enum and getting corresponding int value

I have an enum and I have an integer value associated to each. One of my function accepts that enum. In the function body, I want to fetch the associated int value. How I am doing it right now is it to create a map (with enum as key, and integer code as value) in the static block and use this map to get code corresponding to an enum. Is this the right way of doing it ? Or is there any better established way to achieve the same ?
public enum TAXSLAB {
SLAB_A(1),
SLAB_B(2),
SLAB_C(5);
private static final Map<TAXSLAB, Integer> lookup = new HashMap<TAXSLAB, Integer>();
static {
for(TAXSLAB w : EnumSet.allOf(TAXSLAB.class)) {
lookup.put(w, w.getCode());
}
}
private int code;
private TAXSLAB(int code) {
this.code = code;
}
public int getCode() {
return code;
}
public static int getCode(TAXSLAB tSlab) {
return lookup.get(tSlab);
}
}
Here is the related SO post. But here answer is suggesting to create the map with int value as key as enum as value. So this can not be used to fetch numeric value using enum without iterating through the map
How to get enum's numeric value?
You do not need the map to retrieve code from an enum object, because the call of TAXSLAB.getCode(s) produces the same value as s.getCode():
TAXSLAB s = ...
int c1 = TAXSLAB.getCode(s);
int c2 = s.getCode();
// c1 == c2 here
int code is a field of enum TAXSLAB object, so you can get it directly.
This works for values associated with an enum from within the enum. If you need to associate a value with an enum outside the enum, the most performant way of doing it is by using EnumMap class designed specifically for this purpose.

Using integer values and String identifier in an Enum

So I currently have two enums:
public enum AuthorizationLevel
{
FULL,
HALF,
NONE;
};
public enum DatabaseLoggingLevel
{
HIGH,
MED,
LOW,
AUTH_ONLY,
NONE
}
I want to be able to associate integers with the values in the enums so that I can have code like so:
if(databaseLoggingLevel < ClassName.DatabaseLoggingLevel.HIGH) return;
This is just so that certain logging is disabled when the level is less than HIGH. I thought about making a helper function that returns an integer value associated with each enum value with a switch statement, but that seems hacky. Is there something I am missing?
You can add an integer instance field to your enum, and add a parameterized constructor:
enum AuthorizationLevel {
FULL(1), HALF(2), NONE(3);
private final int level;
private AuthorizationLevel(int level) {
this.level = level;
}
public int getLevel() {
return level;
}
};
Note that there is an ordinal() method which will give you position of your enum constants, but you should avoid using it. Again, quoting Effective Java Item - 31 (Use instance fields instead of ordinal):
If the constants are reordered, the numberOfMusicians method will
break. If you want to add a second enum constant associated with an
int value that you’ve already used, you’re out of luck.
Also, you can’t add a constant for an int value without adding
constants for all intervening int values. For example, suppose you
want to add a constant representing a triple quartet, which consists
of twelve musicians. There is no standard term for an ensemble
consisting of eleven musicians, so you are forced to add a dummy
constant for the unused int value (11). At best, this is ugly. If many
int values are unused, it’s impractical.
Modify the constructor of your enum to add the Integer value.
public enum DatabaseLoggingLevel {
HIGH(1),
MED(2),
LOW(3),
AUTH_ONLY(4),
NONE(5);
private final Integer value;
//For getByValue(). See Rohit's comment
private static final DatabaseLoggingLevel[] VALUES = DatabaseLoggingLevel.values();
private DatabaseLoggingLevel(Integer value) {
this.value = value;
}
public Integer getValue() {
return this.value;
}
//Bonus : getter by value:
public static DatabaseLoggingLevel getByValue(Integer value) {
for(DatabaseLoggingLevel e: VALUES) {
if(e.getValue().equals(value)) {
return e;
}
}
return null;
}
}
public enum DatabaseLoggingLevel
{
HIGH(1),
MED(2),
LOW(3),
AUTH_ONLY(4),
NONE(5)
private int code;
private DatabaseLoggingLevel(int code) {
this.code = code;
}
public int getCode() { return code; }
}
Use the ordinal() method. It gives you the position of the Value in the enum.
Rather than programming this in terms of "enums are numbers", program this in terms of "enums are smart". You can associate numbers with enums (after all, enums are instances of regular Java classes), but make that number private. Then you can add this method to the enum:
public boolean isAboveOrEqualTo(DatabaseLoggingLevel level) {
...
}
Then your conditional would look like this:
if (databaseLoggingLevel.isAboveOrEqualTo(ClassName.DatabaseLoggingLevel.HIGH)) {
...
}
Here is an explanation of how to associate numbers with enums: link.
While both of the answers given already will do what you want I would recommend looking at Log4J as an alternative to rolling your own logging levels
http://www.tutorialspoint.com/log4j/log4j_overview.htm

Enum relating to a string array that was read from file

I've received a working code (in Java, 1.7) that does the following:
load an array of strings (a list of blood test names) from a file into a string array member (using Properties and FileInputStream). The file can change the strings but the meaning stays the same (for example: a test can be called "abc" and in another run it is called "zzz"). I've got an enum class that enumerates the test names. The enum strings aren't the same as the inputted strings (since the latter can change).
file bloodtest.names contains:
bloodTestNames=abc;def;123;
code:
public enum BloodTestNames {
AAA,BBB,CCC;
}
Properties props = new Properties();
FileInputStream fis = new FileInputStream("bloodtest.names");
props.load(fis);
String testName[]=props.getProperty("bloodTestNames").toString().split(";");
Now to the questions:
Question 1:
I need to return the string that was set in the file when I know the test name (for instance: return "def" for value BBB). What's the best of doing that?
the best way I've come up with is:
return testName[BloodTestNames.BBB.ordinal()]
Question 2: if BBB is not known in compile time - how do I accomplish the same target?
Three points:
* I'm a veteran at C but a newbie with Java. Any Do's and Don't are welcome. Assume my Java knowledge is zero.
* I don't total re-factoring is that's what's needed here.
* I've probably forgot to mention important details, please ask and I'll feel the missing gaps
I'll first assume you do need enum constants for modeling this use-case because you have some sort of specific code to be executed for each kind of blood test (otherwise, a simple set of strings would be enough and more flexible, since you don't need to know the number of tests upfront or care about their names).
Q1: Since Java enums are a little more than a sequence of values, you can make full use of their object oriented nature.
public enum BloodTest {
AAA, BBB, CCC;
private static String[] names;
public static void setNames(String[] names) {
if (BloodTest.names != null)
throw new IllegalStateException("You can only set the names once");
if (names.length != values().length)
throw new IllegalArgumentException("Wrong number of names");
BloodTest.names = names;
}
#Override
public String toString() {
return names[ordinal()];
}
}
Now all you need to do is to initialize your enum by calling BloodTest.setNames(namesFromConfiguration) and then you can get the string representation of each constant by calling the standard toString() method on it: BloodTest.BBB.toString().
Since the initial assumption was that you have some specific logic for each of the test types, I would suggest that logic (as well as the required properties) will also be encapsulated in the enum itself or the enum constants; e.g.:
public enum BloodTest {
AAA(10) {
#Override
public boolean isRequired(MedicalRecord medicalRecord) {
return medicalRecord.includes("someDisease");
}
},
BBB(15) {
#Override
public boolean isRequired(MedicalRecord medicalRecord) {
return ! medicalRecord.hasTakenBloodTestsLately();
}
},
CCC(20) { // ... also implements the abstract method and so on
private final int threshold;
private BloodTest(int threshold) {
this.threshold = threshold;
}
public boolean hasPassed(int value) {
return value <= threshold;
}
public abstract boolean isRequired(MedicalRecord medicalRecord);
// ... same as above
}
Now, once you get a reference to some BloodTest, you can check whether that specific test passed by invoking the corresponding method without switching and having the logic spread around the client code:
BloodTest bloodTest = BloodTest.valueOf(someString); // someString can be "AAA", "BBB" or "CCC"
// no matter which constant this is, you use it as an object and rely on polymorphism
if (bloodTest.hasPassed(someValue)) { // ... do something
Q2: Your question 2 kind of "questions" my initial assumption regarding your actual need for an enum. If there's a chance you'll need to dynamically handle blood tests that you don't know about yet, then you can't use an enum.
In other words, if your code does not have any switch or if/else if blocks to handle each blood test, an enum is a really bad choice for your use case.
However, if it does, than I'd recommend refactoring the code to include the logic in the enum itself as in the above example, rather than in switch/if blocks; moreover, if your switch has a default case (or your if has a final else block), this can still be modeled in the enum itself, for instance by adding a DEFAULT constant as a fallback.
Make the whole thing settings driven: Add a statuc method to load in settings of what string maps to what enum and add a factory method that uses these settings:
public enum BloodTestNames {
AAA,BBB,CCC;
private static Map<String, BloodTestNames> map = new HashMap<String, BloodTestNames>();
public static void addAlias(String alias, String name) {
map.put(alias, valueOf(name));
}
public static BloodTestNames getByAluas(String alias) {
if (map.containsKey(alias))
return map.get(alias);
// own name assumed to be mapped
return valueOf(alias);
}
}
On startup, repeatedly call BloodTestNames.addAlias() based on some settings file to load the mappings.
When you're reading the saved file, use BloodTestNames.getByAlias() to return the enum for a given string value.
You would do well to name your class in the singular, and drop "Name", ie BloodTest - name the class for what each enum is (all enums have a "name" which is the coded instance name).
A short extract from one of my enum class :
public enum TypesStructurelsE {
SOURCE("SRC"),
COLONNE("COL");
private String code;
TypesStructurelsE(final String code1) {
code = code1;
}
/** #return String */
public String getCode() {
return code;
}
public void setCode(final String newCode) {
code = newCode;
}
}
. . In other class
if(TypesStructurelsE.SOURCE.getCode().equal(testName[i])){ // can be "COL" or "SRC"
//
;
}
... changing value :
TypesStructurelsE.SOURCE.setCode("SOURCE_NEW");
So, if your properties file change, you have just to compile with the new symbole (SRC --> SOURCE) no more

What is the reason for java.lang.IllegalArgumentException: No enum const class even though iterating through values() works just fine?

This question is basically an extension of my previous question . I asked the previous question to be sure that the Enum constants are populated when the class loads . Here's is my class again with the addition of a simple method getByName :
public enum PropName {
CONTENTS("contents"),
USE_QUOTES("useQuotes"),
ONKEYDOWN("onkeydown"),
BROWSER_ENTIRE_TABLE("browseEntireTable"),
COLUMN_HEADINGS("columnHeadings"),
PAGE_SIZE("pageSize"),
POPUP_TITLE("popupTitle"),
FILTER_COL("filterCol"),
SQL_SELECT("sqlSelect"),
;
private String name;
private PropName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public static PropName getByName(String name){
return PropName.valueOf(name);
}
}
A call to the method getByName("columnHeadings") is throwing java.lang.IllegalArgumentException: No enum const class labware.web.component.limsgrid.PropName.columnHeadings but if I replace this method with the following code it just works .
public static PropName getByName(String name){
for(PropName prop : values()){
if(prop.getName().equals(name)){
return prop;
}
}
throw new IllegalArgumentException(name + " is not a valid PropName");
}
Any ideas as to what I am doing wrong here ?
Enum.valueOf() only checks the constant name, so you need to pass it "COLUMN_HEADINGS" instead of "columnHeadings". Your name property has nothing to do with Enum internals.
To address the questions/concerns in the comments:
The enum's "builtin" (implicitly declared) valueOf(String name) method will look up an enum constant with that exact name. If your input is "columnHeadings", you have (at least) three choices:
Forget about the naming conventions for a bit and just name your constants as it makes most sense: enum PropName { contents, columnHeadings, ...}. This is obviously the most convenient.
Convert your camelCase input into UPPER_SNAKE_CASE before calling valueOf, if you're really fond of naming conventions.
Implement your own lookup method instead of the builtin valueOf to find the corresponding constant for an input. This makes most sense if there are multiple possible mappings for the same set of constants.
That's because you defined your own version of name for your enum, and getByName doesn't use that.
getByName("COLUMN_HEADINGS") would probably work.
Instead of defining: COLUMN_HEADINGS("columnHeadings")
Try defining it as: COLUMNHEADINGS("columnHeadings")
Then when you call getByName(String name) method, call it with the upper-cased String like this: getByName(myStringVariable.toUpperCase())
I had the same problem as you, and this worked for me.
I had parsing enum problem when i was trying to pass Nullable Enum that we get from Backend.
Of course it was working when we get value, but it was problem when the null comes up.
java.lang.IllegalArgumentException: No enum constant
Also the problem was when we at Parcelize read moment write some short if.
My solution for this was
1.Create companion object with parsing method.
enum class CarsType {
#Json(name = "SMALL")
SMALL,
#Json(name = "BIG")
BIG;
companion object {
fun nullableValueOf(name: String?) = when (name) {
null -> null
else -> valueOf(name)
}
}
}
2. In Parcerable read place use it like this
data class CarData(
val carId: String? = null,
val carType: CarsType?,
val data: String?
) : Parcelable {
constructor(parcel: Parcel) : this(
parcel.readString(),
CarsType.nullableValueOf(parcel.readString()),
parcel.readString())

Categories