How should I store this data in a Java enum? - java

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

Related

Java Enum Constructor Undefined

Why am i getting an error "Constructor is undefined" is it in my eclipse IDE?
is there something wrong with my code?
public enum EnumHSClass {
PALADIN ("Paladin"),ROUGE("ROUGE");
}
If you expect your enums to have parameters, you need to declare a constructor and fields for those parameters.
public enum EnumHSClass {
PALADIN ("Paladin"),ROUGE("ROUGE");
private final String name;
private EnumHSClass(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
You need to provide a constructor in your enum like:
public enum EnumHSClass {
PALADIN("Paladin"), ROUGE("ROUGE");
String value;
EnumHSClass(String value) {
this.value = value;
}
}
Note: The constructor for an enum type must be package-private or
private access. It automatically creates the constants that are
defined at the beginning of the enum body. You cannot invoke an enum
constructor yourself.
Ref : http://docs.oracle.com/javase/tutorial/java/javaOO/enum.html
Enums have constructors too, but only with either private or default visibility:
public enum EnumHSClass {
PALADIN ("Paladin"),ROUGE("ROUGE");
private EnumHSClass(String s) {
// do something with s
}
}
You may want to declare a field and create a getter for it, and set the field in the constructor.
Also note that the name of the enum instance is available for free via the (implicit) name() method that all enums have - maybe you can use that instead.
Your code should look like this:
public enum EnumHSClass {
PALADIN ("Paladin"), ROUGE("ROUGE");
private String name;
private EnumHSClass(String name) {
this.name = name;
}
}
public enum Days {
MONDAY(1), TUESDAY(2);
int val;
Days (int val) {
this.val = val;
}
}

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

Looking up enum label by value

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.

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.

How can I lookup a Java enum from its String value?

I would like to lookup an enum from its string value (or possibly any other value). I've tried the following code but it doesn't allow static in initialisers. Is there a simple way?
public enum Verbosity {
BRIEF, NORMAL, FULL;
private static Map<String, Verbosity> stringMap = new HashMap<String, Verbosity>();
private Verbosity() {
stringMap.put(this.toString(), this);
}
public static Verbosity getVerbosity(String key) {
return stringMap.get(key);
}
};
Use the valueOf method which is automatically created for each Enum.
Verbosity.valueOf("BRIEF") == Verbosity.BRIEF
For arbitrary values start with:
public static Verbosity findByAbbr(String abbr){
for(Verbosity v : values()){
if( v.abbr().equals(abbr)){
return v;
}
}
return null;
}
Only move on later to Map implementation if your profiler tells you to.
I know it's iterating over all the values, but with only 3 enum values it's hardly worth any other effort, in fact unless you have a lot of values I wouldn't bother with a Map it'll be fast enough.
You're close. For arbitrary values, try something like the following:
public enum Day {
MONDAY("M"), TUESDAY("T"), WEDNESDAY("W"),
THURSDAY("R"), FRIDAY("F"), SATURDAY("Sa"), SUNDAY("Su"), ;
private final String abbreviation;
// Reverse-lookup map for getting a day from an abbreviation
private static final Map<String, Day> lookup = new HashMap<String, Day>();
static {
for (Day d : Day.values()) {
lookup.put(d.getAbbreviation(), d);
}
}
private Day(String abbreviation) {
this.abbreviation = abbreviation;
}
public String getAbbreviation() {
return abbreviation;
}
public static Day get(String abbreviation) {
return lookup.get(abbreviation);
}
}
with Java 8 you can achieve with this way:
public static Verbosity findByAbbr(final String abbr){
return Arrays.stream(values()).filter(value -> value.abbr().equals(abbr)).findFirst().orElse(null);
}
#Lyle's answer is rather dangerous and I have seen it not work particularly if you make the enum a static inner class. Instead I have used something like this which will load the BootstrapSingleton maps before the enums.
Edit this should not be a problem any more with modern JVMs (JVM 1.6 or greater) but I do think there are still issues with JRebel but I haven't had a chance to retest it.
Load me first:
public final class BootstrapSingleton {
// Reverse-lookup map for getting a day from an abbreviation
public static final Map<String, Day> lookup = new HashMap<String, Day>();
}
Now load it in the enum constructor:
public enum Day {
MONDAY("M"), TUESDAY("T"), WEDNESDAY("W"),
THURSDAY("R"), FRIDAY("F"), SATURDAY("Sa"), SUNDAY("Su"), ;
private final String abbreviation;
private Day(String abbreviation) {
this.abbreviation = abbreviation;
BootstrapSingleton.lookup.put(abbreviation, this);
}
public String getAbbreviation() {
return abbreviation;
}
public static Day get(String abbreviation) {
return lookup.get(abbreviation);
}
}
If you have an inner enum you can just define the Map above the enum definition and that (in theory) should get loaded before.
And you can't use valueOf()?
Edit: Btw, there is nothing stopping you from using static { } in an enum.
In case it helps others, the option I prefer, which is not listed here, uses Guava's Maps functionality:
public enum Vebosity {
BRIEF("BRIEF"),
NORMAL("NORMAL"),
FULL("FULL");
private String value;
private Verbosity(final String value) {
this.value = value;
}
public String getValue() {
return this.value;
}
private static ImmutableMap<String, Verbosity> reverseLookup =
Maps.uniqueIndex(Arrays.asList(Verbosity.values()), Verbosity::getValue);
public static Verbosity fromString(final String id) {
return reverseLookup.getOrDefault(id, NORMAL);
}
}
With the default you can use null, you can throw IllegalArgumentException or your fromString could return an Optional, whatever behavior you prefer.
since java 8 you can initialize the map in a single line and without static block
private static Map<String, Verbosity> stringMap = Arrays.stream(values())
.collect(Collectors.toMap(Enum::toString, Function.identity()));
public enum EnumRole {
ROLE_ANONYMOUS_USER_ROLE ("anonymous user role"),
ROLE_INTERNAL ("internal role");
private String roleName;
public String getRoleName() {
return roleName;
}
EnumRole(String roleName) {
this.roleName = roleName;
}
public static final EnumRole getByValue(String value){
return Arrays.stream(EnumRole.values()).filter(enumRole -> enumRole.roleName.equals(value)).findFirst().orElse(ROLE_ANONYMOUS_USER_ROLE);
}
public static void main(String[] args) {
System.out.println(getByValue("internal role").roleName);
}
}
Perhaps, take a look at this. Its working for me.
The purpose of this is to lookup 'RED' with '/red_color'.
Declaring a static map and loading the enums into it only once would bring some performance benefits if the enums are many.
public class Mapper {
public enum Maps {
COLOR_RED("/red_color", "RED");
private final String code;
private final String description;
private static Map<String, String> mMap;
private Maps(String code, String description) {
this.code = code;
this.description = description;
}
public String getCode() {
return name();
}
public String getDescription() {
return description;
}
public String getName() {
return name();
}
public static String getColorName(String uri) {
if (mMap == null) {
initializeMapping();
}
if (mMap.containsKey(uri)) {
return mMap.get(uri);
}
return null;
}
private static void initializeMapping() {
mMap = new HashMap<String, String>();
for (Maps s : Maps.values()) {
mMap.put(s.code, s.description);
}
}
}
}
Please put in your opinons.
If you want a default value and don't want to build lookup maps, you can create a static method to handle that.
This example also handles lookups where the expected name would start with a number.
public static final Verbosity lookup(String name) {
return lookup(name, null);
}
public static final Verbosity lookup(String name, Verbosity dflt) {
if (StringUtils.isBlank(name)) {
return dflt;
}
if (name.matches("^\\d.*")) {
name = "_"+name;
}
try {
return Verbosity.valueOf(name);
} catch (IllegalArgumentException e) {
return dflt;
}
}
If you need it on a secondary value, you would just build the lookup map first like in some of the other answers.
You can define your Enum as following code :
public enum Verbosity
{
BRIEF, NORMAL, FULL, ACTION_NOT_VALID;
private int value;
public int getValue()
{
return this.value;
}
public static final Verbosity getVerbosityByValue(int value)
{
for(Verbosity verbosity : Verbosity.values())
{
if(verbosity.getValue() == value)
return verbosity ;
}
return ACTION_NOT_VALID;
}
#Override
public String toString()
{
return ((Integer)this.getValue()).toString();
}
};
See following link for more clarification
You can use the Enum::valueOf() function as suggested by Gareth Davis & Brad Mace above, but make sure you handle the IllegalArgumentException that would be thrown if the string used is not present in the enum.

Categories

Resources