Best way to implement an enum class in java - java

I'm trying to get the best way to implement a file with all my static enums, without using any getters and setters, just static info, I achieve this in PHP like in the example below, do you really need getters and setters in java?
final class EnumTrade {
const buy = 1;
const sell = 2;
}
final class EnumGender {
const male = 1;
const female = 2;
}
final class EnumHttpMethod {
const get = 1;
const post = 2;
}

public enum EnumTrade {
BUY, SELL
}
and so on.
Edit: If the number matters, do:
public enum EnumTrade {
BUY(1), SELL(2)
}

in java enum not necessary to have getter and setter these are used for normal POJO or beans
sample enum can be:
public enum EventRecurringType {
YEARLY("1"),
QUARTERLY("2"),
MONTHLY("3"),
WEEKLY("4"),
DAILY("5"),
NONE("0");
private String value;
EventRecurringType(String value) {
this.value = value;
}
public String getValue() {
return value;
}
#Override
public String toString() {
return this.getValue();
}
public static EventRecurringType getEnum(String value) {
if(value == null)
throw new IllegalArgumentException();
for(EventRecurringType v : values())
if(value.equalsIgnoreCase(v.getValue())) return v;
throw new IllegalArgumentException();
}
}

public enum EnumTrade
{
BUY,
SELL,
}
If all you need is the ordinal values of the enums, you can access those directly via EnumTrade.BUY.ordinal
If you want to store other data in the enum, do something like this (expanding as needed):
public enum EnumGender
{
MALE(1),
FEMALE(2);
private final int value;
private EnumGender(String value)
{
this.value = value;
}
public int getValue()
{
return this.value;
}
//In case you need to grab an enum by the value constant
public getEnumGender(int value)
{
switch(value)
{
case 1:
return EnumGender.MALE;
case 2:
default:
return EnumGender.FEMALE;
}
}
}

For sake of completeness and the fact answers pop in while writing i changed my original answer to mention you could store all your enums in one java class.
=> It is way better to have them stored in own files like user Tichodroma suggests
However translating your exmaple code you could build this in Java:
public class MyEnums {
public enum EnumTrade{
BUY, SELL
}
public enum EnumGender{
MALE, FEMALE
}
public enum EnumHttpMethod{
GET, POST
}
}
And then use the different enums from outside like this:
MyEnums.EnumTrade.BUY

public enum MyConst{ BUY(1), SELL(2), MALE(3), FEMALE(4), GET(5), POST(6);
public final int value;
MyConst(int value) {
this.value = value;
}
public int getValue() {
return value;
}
};
or Just go with
public enum MyConst{ BUY(1), SELL(2) }; and same for MALE, FEMALE ....

Related

Getting an enum from an integer + more abstraction questions

I have an enumerator that takes an int and a string as fields. These are accessible via static methods or directly from the enumerator "instance" (not familiar with the proper wording for this). Here is what I mean by that:
public enum CreatureType {
POKE_PIG(1, "Piggley"), POKE_COW(2, "Cowbert");
private int number;
private String name;
CreatureType(int number, String name) {
this.number = number;
this.name = name;
}
public int getNumber() {
return number;
}
public String getName() {
return name;
}
public static String getName(CreatureType type) {
return type.getName();
}
public static int getNumber(CreatureType type) {
return type.getNumber();
}
But now I need to get a CreatureType FROM it's int. So here's my pseudocode I've written that is my best guess at how to do this:
public static CreatureType getCreatureType(int number) {
switch (number) {
case 1:
return CreatureType.POKE_PIG;
case 2:
return CreatureType.POKE_COW;
default:
break;
}
return null;
}
This feels weird though. I don't love this technique, and even though in theory it should work, I feel like there HAS to be a better way of doing this. I don't have these enums stored in a list or set or anything so I can't iterate through them, and I'm just blanking on the proper way to grab this.
Your switch-case solution is more efficient, but the following code is easier to maintain as it does not need adjustment when adding a new enum value:
public static CreatureType getCreatureType(int number) {
for(CreatureType creatureType : CreatureType.values()) {
if(creatureType.number == number) {
return creatureType;
}
}
return null; // No match.
}

Feature or bug: unable to override enum method with default implementation of UnsupportedOperationException

I have an application that uses an enum for the options. Some of the options should be able to have some state: an int value or a String value. (I know that in general an enum should only have final attributes, but there are use cases in which the value of the attribute is only known at runtime, and you can't pass arguments for the constructor of an enum at runtime.) I would like the default implementation of the getters and setters for these options to be implemented by throwing a UnsupportedOperationException, like this (part of the original code):
public enum FileTreeOption1 {
HUMAN_READABLE, DATE, DIRS_ONLY, FILES_ONLY,
DEPTH{
#Override
public void setIntValue(int value){
this.intValue = value;
}
#Override
public int getIntValue(){
return intValue;
}
};
private int intValue;
public void setIntValue(int value) {
throw new UnsupportedOperationException("setIntValue not available for " + this.name());
}
public int getIntValue() {
throw new UnsupportedOperationException("getIntValue not available for " + this.name());
}
}
However, when I try to compile this, I get these error messages (in java 11):
FileTreeOption1.java:7: error: intValue has private access in FileTreeOption1
this.intValue = value;
^
FileTreeOption1.java:11: error: non-static variable intValue cannot be referenced from a static context
return intValue;
^
2 errors
Especially the second error is a strange one: there is no static context.
As a work around, I have managed to get my code working as shown below. But my question is: shouldn't the code above be able to compile?
Work around:
public enum FileTreeOption2 {
HUMAN_READABLE, DATE, DIRS_ONLY, FILES_ONLY,
DEPTH(true);
private boolean useIntValue;
private int intValue;
FileTreeOption2( boolean useIntValue){
this.useIntValue = useIntValue;
}
FileTreeOption2(){}
public void setIntValue(int value) {
if(useIntValue){
this.intValue = value;
} else {
throw new UnsupportedOperationException("setIntValue not available for " + this.name());
}
}
public int getIntValue() {
if(useIntValue){
return this.intValue;
} else {
throw new UnsupportedOperationException("getIntValue not available for " + this.name());
}
}
}
Thanks to the help of Nikolai, I have just found out that not only can you override methods in an enum constant, but you can add variables to them too. So this one actually works:
public enum FileTreeOption1 {
HUMAN_READABLE, DATE, DIRS_ONLY, FILES_ONLY,
DEPTH{
private int intValue; // attribute only available to DEPTH
#Override
public void setIntValue(int value){
this.intValue = value;
}
#Override
public int getIntValue(){
return intValue;
}
};
public void setIntValue(int value) {
throw new UnsupportedOperationException("setIntValue not available for " + this.name());
}
public int getIntValue() {
throw new UnsupportedOperationException("getIntValue not available for " + this.name());
}
public static void main(String args[]){
FileTreeOption1 option = FileTreeOption1.DEPTH;
option.setIntValue(3);
System.out.println(option.getIntValue()); // 3
option = FileTreeOption1.DATE;
System.out.println(option.getIntValue()); // UnsupportedOperationException
}
}
You must change intValue visibility from private to protected to make the code compile
For some more context: the code below does compile, so you are in fact allowed to have state in an enum, and to implement one or more of the methods in a different way for one or more of the constants:
public enum FileTreeOption1 {
HUMAN_READABLE, DATE, DIRS_ONLY, FILES_ONLY,
DEPTH{
#Override
public void setIntValue(int value){
throw new UnsupportedOperationException();
}
#Override
public int getIntValue(){
return 1;
}
} ;
private int intValue;
public void setIntValue(int value) {
this.intValue = value;
}
public int getIntValue() {
return intValue;
}
}
WRONG:
Short answer to your question - no. The code should not compile.
Explanation:
First of all - enum cannot be extended. When you're trying to define your DEPTH{ - you're actually creating anonymous class that extends your enum. In Java it's not possilbe. The same also is a reason to first error: private int intValue; is private field - thus it is not visible inside subclasses.
The code does not compile because private int intValue; has private modifier and when you create your DEPTH{ - you cannot access private field there. Only public or protected.
The static context - Java enums are public static final by default (You can see this in the outline pane in Eclipse).

How to return enum value in java

How can I return enums like this?
Before I was returing an int with 0 if no, 1 if yes and 2 if other. But this wasn't good way to do. So how should it be done. My code:
class SomeClass{
public enum decizion{
YES, NO, OTHER
}
public static enum yourDecizion(){
//scanner etc
if(x.equals('Y')){
return YES;
}
else if (x.equals('N')){
return NO;
}
else{
return OTHER;
}
}
}
I don't what the "//scanner etc." does, but the methods return type should be decizion:
public static decizion yourDecizion() { ... }
Furthermore, you can add the Y, N, etc. values to the enum constants:
public enum decizion{
YES("Y"), NO("N"), OTHER;
String key;
decizion(String key) { this.key = key; }
//default constructor, used only for the OTHER case,
//because OTHER doesn't need a key to be associated with.
decizion() { }
static decizion getValue(String x) {
if ("Y".equals(x)) { return YES; }
else if ("N".equals(x)) { return NO; }
else if (x == null) { return OTHER; }
else throw new IllegalArgumentException();
}
}
Then, in the method, you can just do:
public static decizion yourDecizion() {
...
String key = ...
return decizion.getValue(key);
}
I think you should do something like these, an enum class. Then you can add as many types you want and the method yourDecizion() will return the enum type depending on the given parameter.
public enum SomeClass {
YES(0),
NO(1),
OTHER(2);
private int code;
private SomeClass(int code) {
this.code = code;
}
public int getCode() {
return code;
}
public static SomeClass yourDecizion(int x) {
SomeClass ret = null;
for (SomeClass type : SomeClass.values()) {
if (type.getCode() == x)
ret = type;
}
return ret;
}
}
Change your code to:
class SomeClass{
public enum decizion {
YES, NO, OTHER
}
public static decizion yourDecizion(){
//scanner etc
if(x.equals('Y')){
return decizion.YES;
}
else if (x.equals('N')){
return decizion.NO;
}
else{
return decizion.OTHER;
}
}
}
Note: The method return type must be decizion instead of enum and decizion should have an upper case name (as all classes should).
You can get the value in below way. Here you have private constructor which will initialize the value you want to set and when the instance method value gets invoked simply return this.key.
public class Application {
enum Day {
MONDAY("Monday"), TUESDAY("Tuesday");
String key;
Day(String str) {
key = str;
}
public String value() {
return this.key;
}
}
public static void main(String[] args) {
System.out.println(Day.MONDAY.value());
}
}

Convert integer value to matching Java Enum

I've an enum like this:
public enum PcapLinkType {
DLT_NULL(0)
DLT_EN10MB(1)
DLT_EN3MB(2),
DLT_AX25(3),
/*snip, 200 more enums, not always consecutive.*/
DLT_UNKNOWN(-1);
private final int value;
PcapLinkType(int value) {
this.value= value;
}
}
Now I get an int from external input and want the matching input - throwing an exception if a value does not exist is ok, but preferably I'd have it be DLT_UNKNOWN in that case.
int val = in.readInt();
PcapLinkType type = ???; /*convert val to a PcapLinkType */
You would need to do this manually, by adding a a static map in the class that maps Integers to enums, such as
private static final Map<Integer, PcapLinkType> intToTypeMap = new HashMap<Integer, PcapLinkType>();
static {
for (PcapLinkType type : PcapLinkType.values()) {
intToTypeMap.put(type.value, type);
}
}
public static PcapLinkType fromInt(int i) {
PcapLinkType type = intToTypeMap.get(Integer.valueOf(i));
if (type == null)
return PcapLinkType.DLT_UNKNOWN;
return type;
}
There's a static method values() which is documented, but not where you'd expect it: http://docs.oracle.com/javase/tutorial/java/javaOO/enum.html
enum MyEnum {
FIRST, SECOND, THIRD;
private static MyEnum[] allValues = values();
public static MyEnum fromOrdinal(int n) {return allValues[n];}
}
In principle, you can use just values()[i], but there are rumors that values() will create a copy of the array each time it is invoked.
You will have to make a new static method where you iterate PcapLinkType.values() and compare:
public static PcapLinkType forCode(int code) {
for (PcapLinkType typŠµ : PcapLinkType.values()) {
if (type.getValue() == code) {
return type;
}
}
return null;
}
That would be fine if it is called rarely. If it is called frequently, then look at the Map optimization suggested by others.
if you have enum like this
public enum PcapLinkType {
DLT_NULL(0)
DLT_EN10MB(1)
DLT_EN3MB(2),
DLT_AX25(3),
DLT_UNKNOWN(-1);
private final int value;
PcapLinkType(int value) {
this.value= value;
}
}
then you can use it like
PcapLinkType type = PcapLinkType.values()[1]; /*convert val to a PcapLinkType */
You can do something like this to automatically register them all into a collection with which to then easily convert the integers to the corresponding enum. (BTW, adding them to the map in the enum constructor is not allowed. It's nice to learn new things even after many years of using Java. :)
public enum PcapLinkType {
DLT_NULL(0),
DLT_EN10MB(1),
DLT_EN3MB(2),
DLT_AX25(3),
/*snip, 200 more enums, not always consecutive.*/
DLT_UNKNOWN(-1);
private static final Map<Integer, PcapLinkType> typesByValue = new HashMap<Integer, PcapLinkType>();
static {
for (PcapLinkType type : PcapLinkType.values()) {
typesByValue.put(type.value, type);
}
}
private final int value;
private PcapLinkType(int value) {
this.value = value;
}
public static PcapLinkType forValue(int value) {
return typesByValue.get(value);
}
}
I know this question is a few years old, but as Java 8 has, in the meantime, brought us Optional, I thought I'd offer up a solution using it (and Stream and Collectors):
public enum PcapLinkType {
DLT_NULL(0),
DLT_EN3MB(2),
DLT_AX25(3),
/*snip, 200 more enums, not always consecutive.*/
// DLT_UNKNOWN(-1); // <--- NO LONGER NEEDED
private final int value;
private PcapLinkType(int value) { this.value = value; }
private static final Map<Integer, PcapLinkType> map;
static {
map = Arrays.stream(values())
.collect(Collectors.toMap(e -> e.value, e -> e));
}
public static Optional<PcapLinkType> fromInt(int value) {
return Optional.ofNullable(map.get(value));
}
}
Optional is like null: it represents a case when there is no (valid) value. But it is a more type-safe alternative to null or a default value such as DLT_UNKNOWN because you could forget to check for the null or DLT_UNKNOWN cases. They are both valid PcapLinkType values! In contrast, you cannot assign an Optional<PcapLinkType> value to a variable of type PcapLinkType. Optional makes you check for a valid value first.
Of course, if you want to retain DLT_UNKNOWN for backward compatibility or whatever other reason, you can still use Optional even in that case, using orElse() to specify it as the default value:
public enum PcapLinkType {
DLT_NULL(0),
DLT_EN3MB(2),
DLT_AX25(3),
/*snip, 200 more enums, not always consecutive.*/
DLT_UNKNOWN(-1);
private final int value;
private PcapLinkType(int value) { this.value = value; }
private static final Map<Integer, PcapLinkType> map;
static {
map = Arrays.stream(values())
.collect(Collectors.toMap(e -> e.value, e -> e));
}
public static PcapLinkType fromInt(int value) {
return Optional.ofNullable(map.get(value)).orElse(DLT_UNKNOWN);
}
}
As #MeBigFatGuy says, except you can make your static {...} block use a loop over the values() collection:
static {
for (PcapLinkType type : PcapLinkType.values()) {
intToTypeMap.put(type.getValue(), type);
}
}
You could add a static method in your enum that accepts an int as a parameter and returns a PcapLinkType.
public static PcapLinkType of(int linkType) {
switch (linkType) {
case -1: return DLT_UNKNOWN
case 0: return DLT_NULL;
//ETC....
default: return null;
}
}
This is what I use:
public enum Quality {ENOUGH,BETTER,BEST;
private static final int amount = EnumSet.allOf(Quality.class).size();
private static Quality[] val = new Quality[amount];
static{ for(Quality q:EnumSet.allOf(Quality.class)){ val[q.ordinal()]=q; } }
public static Quality fromInt(int i) { return val[i]; }
public Quality next() { return fromInt((ordinal()+1)%amount); }
}
static final PcapLinkType[] values = { DLT_NULL, DLT_EN10MB, DLT_EN3MB, null ...}
...
public static PcapLinkType getPcapLinkTypeForInt(int num){
try{
return values[int];
}catch(ArrayIndexOutOfBoundsException e){
return DLT_UKNOWN;
}
}
This might not be a great solution, but its working for me:
public enum Type {
WATER, FIRE, GRASS;
public static Type getType(int value){
if(value==WATER.ordinal()){
return WATER;
}else if(value==FIRE.ordinal()){
return FIRE;
}else if(value==GRASS.ordinal()){
return GRASS;
}else {
return null;
}
}
}
There is no way to elegantly handle integer-based enumerated types. You might think of using a string-based enumeration instead of your solution. Not a preferred way all the times, but it still exists.
public enum Port {
/**
* The default port for the push server.
*/
DEFAULT("443"),
/**
* The alternative port that can be used to bypass firewall checks
* made to the default <i>HTTPS</i> port.
*/
ALTERNATIVE("2197");
private final String portString;
Port(final String portString) {
this.portString = portString;
}
/**
* Returns the port for given {#link Port} enumeration value.
* #return The port of the push server host.
*/
public Integer toInteger() {
return Integer.parseInt(portString);
}
}

How to convert string result of enum with overridden toString() back to enum?

Given the following java enum:
public enum AgeRange {
A18TO23 {
public String toString() {
return "18 - 23";
}
},
A24TO29 {
public String toString() {
return "24 - 29";
}
},
A30TO35 {
public String toString() {
return "30 - 35";
}
},
}
Is there any way to convert a string value of "18 - 23" to the corresponding enum value i.e. AgeRange.A18TO23 ?
Thanks!
The best and simplest way to do it is like this:
public enum AgeRange {
A18TO23 ("18-23"),
A24TO29 ("24-29"),
A30TO35("30-35");
private String value;
AgeRange(String value){
this.value = value;
}
public String toString(){
return value;
}
public static AgeRange getByValue(String value){
for (final AgeRange element : EnumSet.allOf(AgeRange.class)) {
if (element.toString().equals(value)) {
return element;
}
}
return null;
}
}
Then you just need to invoke the getByValue() method with the String input in it.
You could always create a map from string to value - do so statically so you only need to map it once, assuming that the returned string remains the same over time. There's nothing built-in as far as I'm aware.
According to effective java (2nd ed) item 30, it can be (it is much faster than the loop)
public enum AgeRange {
A18TO23("18-23"),
A24TO29("24-29"),
A30TO35("30-35");
private final String value;
AgeRange(String value){
this.value = value;
}
#Override public String toString(){
return value;
}
private static final Map<String, AgeRange> stringToEnum =
new HashMap<String, AgeRange>();
static {
for (AgeRange r : values()) {
stringToEnum.put(r.toString(), r);
}
}
public static AgeRange getByValue(String value){
return stringToEnum.get(value);
}
}
for (AgeRange ar: EnumSet.allOf(AgeRange)) {
if (ar.toString().equals(inString)) {
myAnswer = ar;
break;
}
}
Or something like that? Just typed in, haven't run through a compiler. Forgive (comment on) typos...
Or use logic like this to build a map once. Avoid iteration at runtime. Good idea, Jon.
The class overrides "toString()" - so, to get the reverse operation, you need to override valueOf() to translate the output of toString() back to the Enum values.
public enum AgeRange {
A18TO23 {
public String toString() {
return "18 - 23";
}
public AgeRange valueOf (Class enumClass, String name) {
return A18T023
}
},
.
.
.
}
Buyer beware - uncompiled and untested...
The mechanism for toString() and valueOf() is a documented part of the API
You could try something like the following?
static AgeRange fromString(String range) {
for (AgeRange ageRange : values()) {
if (range.equals(ageRange.toString())) {
return ageRange;
}
}
return null;
}
Or, as others suggested, using a caching approach:
private static Map<String, AgeRange> map;
private static synchronized void registerAgeRange(AgeRange ageRange) {
if (map == null) {
map = new HashMap<String, AgeRange>();
}
map.put(ageRange.toString(), ageRange);
}
AgeRange() {
registerAgeRange(this);
}
static AgeRange fromString(String range) {
return map.get(range);
}

Categories