Looking up enum label by value - java

I have the following enum in my java android application:
static enum PaymentType
{
Scheme(0), Topup(1), Normal(2), Free(3), Promotion(4), Discount(5), Partial(6),
Refund(7), NoShow(8), Prepay(9), Customer(10), Return(11), Change(12), PettyCash(13),
StateTax(14), LocalTax(15), Voucher(16), Membership(17), Gratuity(18), Overpayment(19),
PrepayTime(20), HandlingFee(21);
private int value;
private PaymentType(int i) {
value = i;
}
public int getValue() {
return value;
}
}
I use this enum alot to find out the integer value of one of these string labels, for example int i = Lookups.PaymentType.Voucher.getValue();.
How can I do this the other way around? I have an integer value from a database and I need to find which string that corresponds to.

You should do something like this (static-init block should be at the end! and in your case just replace "asc" and "desc" with numbers, or add any other field):
public enum SortOrder {
ASC("asc"),
DESC("desc");
private static final HashMap<String, SortOrder> MAP = new HashMap<String, SortOrder>();
private String value;
private SortOrder(String value) {
this.value = value;
}
public String getValue() {
return this.value;
}
public static SortOrder getByName(String name) {
return MAP.get(name);
}
static {
for (SortOrder field : SortOrder.values()) {
MAP.put(field.getValue(), field);
}
}
}
After that, just call:
SortOrder asc = SortOrder.getByName("asc");

To go from an ordinal() index value back to enum:
type = PaymentType.values()[index];
However, keep in mind that this is fragile when the ordinal is stored anywhere else, such as a database. If the index numbers ever change, you'll get invalid results.
For more reliable lookup table, use a Map.

Related

How would I use enum on my project?

I have a class with an instance field lockAction, value 1 is lock and 3 is unlock. I'd like to introduce enum on to my EJB project. How do I got about that?
public enum lockUnlock {
LOCK, //1
UNLOCK, //3
}
you can use something like this.
public enum lockUnlock {
LOCK(1), UNLOCK(3);
int value;
lockUnlock(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}
class Test {
public static void main(String[] args) {
lockUnlock[] b = lockUnlock.values();
for (lockUnlock b1 : b) {
System.out.println(b1 + "........" + b1.getValue());
}
}
}
You could assign a value to the enum like so.
public enum LockUnlock {
LOCK(1), UNLOCK(3);
private final int value;
private LockUnlock(int value) {
this.value = value;
}
public int getValue() { return value; }
}
#eldix_ you can use enums when you know that some of the Constant data in your code can't be changed by the user.
For example.
if you want to show some data in a drop down on the screen like below
as shown in the example, where the drop down values are constants, which client has to select.
we can change this at one place use it any where, without data being changed.

Print Java enum to lower case by default keeping enum constants in uppercase

I have an enum in Java I'd like to serialize, so that when I call it from anywhere in the code, I get the lowercase representation of the name.
Let's say I have the following enum:
public enum Status {
DRAFT, PENDING, COMPLETE;
}
println ("Status=" + Status.DRAFT);
I'd like to get the following:
Status=draft
[Note]: I want to use the enum constants in uppercase, and when requesting the value get the lowercase representation.
I am replying this question myself as i found the solution interesting and could not find a reply in the site. Just in case somebody else looks for a way to solve this.
The solution is simple, just override the Enum toString method like this:
public enum Status {
DRAFT, PENDING, COMPLETE;
#Override
public String toString() {
return name().toLowerCase();
}
}
println ("Status=" + Status.DRAFT);
This would output the name in lower case.
Another solution could be:
public enum Status {
DRAFT, PENDING, COMPLETE;
public String nameLowerCase(){
return name().toLowerCase();
}
}
If you want lower case, you could just use lower case, or mixed case, or whatever makes more sense to you.
public enum Status {
draft, pending, complete;
}
println ("Status=" + Status.draft);
prints
Status=draft
You can use the following Enum class which contains constructor with name and ordinal for each enum constant. You can assign values you need for the enum constant.
public enum Status {
DRAFT(0,"draft"), PENDING(1,"pending"), COMPLETE(2,"complete");
private int key;
private String value;
Status(int key, String value){
this.key = key;
this.value = value;
}
public int getKey() {
return key;
}
public void setKey(int key) {
this.key = key;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
#Override
public String toString(){
return this.value;
}
}
Since we override the toString method, the value which is lowercase is returned.
Using
System.out.print("Status = "+Status.DRAFT);
would print,
Status = draft
and
System.out.print("Status = "+Status.DRAFT.name());
would print
Status = DRAFT

How should I store this data in a Java enum?

What's the best way to store this data in a Java enum?
<select>
<option></option>
<option>Recommend eDelivery</option>
<option>Require eDelivery</option>
<option>Require eDelivery unless justification provided</option>
</select>
I'm new to java and have tried things like
public enum Paperless {
"None" = null,
"Recommend eDelivery" = "Recommend eDelivery",
"Require eDelivery" = "Require eDelivery",
"Require eDelivery unless justification provided" = "Require eDelivery w/out justification"
}
But this doesn't work. I'm considering the possibility of storing a text value that summarizes the option that the user sees on this web page.
Take a look at the enum tutorial, more specifically the Planet example. You can do the same, e.g.
public enum Paperless{
NONE( null ),
RECOMMENDED_DELIVERY( "Recommended delivery" ),
...//put here the other values
REQUIRED_DELIVERY( "Required delivery" );
private String name;
Paperless( String name ){
this.name = name;
}
public String getName(){
return this.name;
}
}
Something like this can work for your case:
public enum PaperLess {
NONE("none"),
RECOMMEND("Recommend eDelivery"),
REQUIRE("Require eDelivery"),
REQUIRE_JUSTIFIED("Require eDelivery unless justification provided");
private String value;
private PaperLess(String value) {
this.value = value;
}
public String getValue() {
return value;
}
}
You can't assign strings to enum values in Java in the way that you are trying.
The way to do it would be:
public enum Paperless {
None(null),
RecommendedDelivery("Recommended Delivery"),
RequireEDelivery("Require eDelivery"),
RequireEDeliveryUnlessJustification("Require eDelivery unless justification provided");
private final String value;
Paperless(String value) {
this.value = value;
}
private String enumValue() { return value; }
public static void main(String[] args) {
for (Paperless p : Paperless.values())
System.out.println("Enum:" + p + "; Value:" + p.enumValue());
}
}
You can't have spaces in the names of members and you can't assign enum values, they are objects, not constants.
The name of the enum must be an identifier (e.g. one-word, not a string)
public enum Paperless {
None,
RecommendEDelivery,
...
}
You can associate string values with them if you want (although you can get the default too that equals to the identifier name, usign the name() method) by associating a String member with the enum type and providing a custom constructor.
public enum Paperless {
None("None"),
RecommendEDelivery("Recommend eDelivery"),
...;
private String myValue;
private Paperless(String name) {myValue=name;)
}
To access that associated string, you need to provide a public accessor method as well.
Java enums aren't constructed in that way. Check out
Java Tutorials: Enum Types
Java - Convert String to enum: #2
Yours might look something like this:
public enum Paperless {
NONE(""),
RECOMMEND("Recommend eDelivery"),
REQUIRE("Require eDelivery"),
REQUIRE_UNLESS("Require eDelivery unless justification provided");
private String text;
Paperless(String text) {
this.text = text;
}
public String getText() {
return this.text;
}
}
public enum Paperless {
NONE("None"),
RECOMMEND("Recommend eDelivery"),
REQUIRE("Require eDelivery"),
REQUIRE_UNLESS("Require eDelivery unless justification provided"),;
private String value;
private Paperless(String value){
this.value=value;
}
public String getValue(){
return this.value;
}
}

Design Issue | Enum to represent combo box options

I need to use an Enum with a combobox (values shown below).
YES (shown as YES on UI, stored in DB as Y)
NO (shown as NO on UI, stored in DB as N)
DEFAULT (shown as "" on UI, stored in DB as null)
The Enum has methods to perform the following -
toString() - to provide the custom String for UI. (showing the combo options)
OptionToDB (static) - Convert a selected option to db value (on save / update)
DBToOption (static)- Convert a DB value to selcted option (while loading the screen)
static enum EnumOption{
YES,NO,DEFAULT;
....
public static EnumOption DBToOption(String val){
if("Y".equals(val)){
return YES;
} else if("N".equals(val)){
return NO;
}else {
return DEFAULT;
}
}
....
}
It works pretty well, but the issue with above methods is that it uses if/else comparison to deduce which option / db value to be returned.
I thought of storing the dbValue as a field in enum but I was not able to reduce the if/else from DBToOption.
Can this if/else be avoided in any way using a better design??
If you store the dbValue as a field in the enum, you can remove the if/else and replace it with a for-loop, although I don't see anything wrong with those if/elses for this particular case:
static enum EnumOption {
YES("Y"),
NO("N"),
DEFAULT("");
private final String value;
private EnumOption(String value) {
this.value = value;
}
public static EnumOption DBToOption(String val) {
for (EnumOption opt : EnumOption.values()) {
if (opt.value.equals(val)) {
return opt;
}
}
return DEFAULT;
}
}
public enum EnumOption {
YES("Y"), NO("N"), DEFAULT("");
private final String value;
private final static Map<String, EnumOption> options;
static {
options = new HashMap<String, EnumOption>();
for (EnumOption opt : EnumOption.values()) {
options.put(opt.value, opt);
}
}
private EnumOption(String value) {
this.value = value;
}
public static EnumOption DBToOption(String val) {
return options.get(val) != null ? options.get(val) : DEFAULT;
}
}
And here is the test that proves it works.
public void testDBToOption() {
assertEquals(EnumOption.NO, EnumOption.DBToOption("N"));
assertEquals(EnumOption.YES, EnumOption.DBToOption("Y"));
assertEquals(EnumOption.DEFAULT, EnumOption.DBToOption(""));
assertEquals(EnumOption.DEFAULT, EnumOption.DBToOption(null));
assertEquals(EnumOption.DEFAULT, EnumOption.DBToOption("R"));
}
So you want to get rid of the remaining if/else ...Are you doing Object Calisthenics?
You could do the following, if you do not have compatibility issues:
public enum EnumOption {
Y("Y", "YES"),
N("N", "NO"),
D("D", "");
private final String dbValue;
private final String uiValue;
private EnumOption(String dbValue, String uiValue) {
this.dbValue = dbValue;
this.uiValue = uiValue;
}
public String getDbValue() {
return this.dbValue;
}
public String uiValue() {
return this.uiValue;
}
public static EnumOption getFromDb(String dbValue) {
return EnumOption.valueOf(dbValue);
}
}
Since each enum value can only occur once, this has at least the same performance as all the other implementations.
For details about the automatically generated valueOf(String) method in enum types, and James DW's solution, you can read up in Josh Bloch's Effective Java Item 30 (Use enums instead of int constants), page 154.

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