Enumeration help/advice - java - java

Is it possible to use an enumeration in the following circumstance:
Let’s say you have a certain amount of predefined 'read types'. Example read types could be: Diagnostic, KWH, MaxDemand, OnPeak, etc. And for each of these read types, there’s a ‘TIMTagNumber’ which is essientally a protocol for retrieving each predefined read type.
For example, TIMTagNumber 1100 would retrieve the read type Diagnostic
TIMTagNumber 1300 would retrieve the read type KWH.
The problem is that a predefined read type can sometimes be retrieved by more than one TIMTagNumber.
I want to create an enumeration ReadType that would define each read type and all TIMTagNumbers that can be used to retrieve that read.
Can you use an enumeration in this way?
public enum ReadType{
KWH(1300)
Diagnostic(1100)
ReadType3(1400, 1401) // This read can be retrieved by both 1400 and 1401
}
If an enumeration is not the way to go, is there an elegant or efficient way to define these read types? The overall desired outcome of all this essientally is being recognizing what type of read it is based on the TIMTagNumbers.
I.E. Given 1400 OR 1401 you would know that it's 'ReadType3'.

Can you do this? Yes. Whether it's the right decision will depend on whether you want to couple these TIMTagNumbers to the read type. If not, a simple Map<Integer, ReadType> will probably suffice.
Here's how you could do it:
public static enum MyEnum {
KWH(1300),
Diagnostic(1100),
ReadType3(1400, 1401);
private Set<Integer> timTagNumbers;
MyEnum(Integer... timTagNumbers) {
this.timTagNumbers = new HashSet<Integer>(Arrays.asList(timTagNumbers));
//add check to make sure that values are unique across all instances
}
public static MyEnum forTIMTagNumber(int num) {
for ( MyEnum readType : values() ) {
if ( readType.timTagNumbers.contains(num) ) {
return readType;
}
}
throw new NoSuchElementException("No ReadType matching TIMTagNumber " + num);
}
}
//...
int timTagNumber = 1400;
ReadType readType = ReadType.forTIMTagNumber(timTagNumber);
As I said above, this style works well when the data and the enum types are intrinsically coupled already. It would not be good for when the enum type is decoupled from the mapped values (e.g. the values are used for one of many ways of serializing the enum) or if the values are configuration-specific or even dynamic (e.g. if they were prices on an item). In these cases it is usually best to externalize this mapping in an EnumMap or Map.

public enum ReadType {
KWH(1300),
Diagnostic(1100),
ReadType3(1400, 1401);
private int[] timTagNumbers;
private ReadType(int ... numbers) {
this.timTagNumbers = numbers;
}
public int[] getTimTagNumbers() {
return timTagNumbers;
}
public static ReadType forTimTagNumber(int n) {
for (ReadType type : values()) {
if (Arrays.binarySearch(type.timTagNumbers, n) != -1) {
return type;
}
}
throw new NoSucheElementException(); // if not found
}
With this you can do
int[] timTagNumbers = ReadType.Diagnostic.getTimTagNumbers(); // [ 1100 ]
and
ReadType type3 = ReadType.forTimTagNumber(1401); // ReadType.ReadType3

You can indeed use enumerations in that way, but your example is missing a private field and a constructor.
Something like:
public enum Bla{
CASE1(100),CASE2(200);
private int amount;
private Bla(int amount) {
this.amount = amount;
}
public Bla getByValue(int value){
switch (value) {
case 100: return CASE1;
case 200: return CASE2;
}
return null;
}
}
I've included a "reverse lookup" method that returns an Enum given the value.
The main advantage is that you can have the rest of your code using "Bla" instead of int's which will guarantee type-safety on your operations, basically, it'll make impossible to pass an invalid int value as a method parameter (and you can use switch statements over enums too, and that's pretty awesome in some usage scenarios).
EDIT: I noticed after I posted that you need more then one int to specify the Enum, but the same logic applies, with the due changes in the methods, of course.

You could do something like the following, when you supply values in the parentheses where the enum variable is declared, it is calling the constructor of the enum. You need to create a different method in the enum itself to get the enum type from the integer value. See below.
public enum ReadType {
KWH(), DIAGNOSTIC(), READTYPE3();
public ReadType getReadType(int num) {
ReadType toReturn = KWH;
switch (num) {
case 1300:
toReturn = KWH;
break;
case 1100:
toReturn = DIAGNOSTIC;
break;
case 1400:
toReturn = READTYPE3;
break;
case 1401:
toReturn = READTYPE3;
break;
}
return toReturn;
}

If you can impose some restrictions like no more than 2 tags can be associated with a read type and each tag is no greater than 2^15, then you can store the two numbers into 1 integer. See this S/O post for more details.

Related

Sorting by translated enum

I'm having a following problem: I have to sort entities by enum parameter. The thing is, that enum name is not equivalent to its translated name, for example, the enum values can be:
enum Sample {
Bus, Car, Train
}
However, let's say in my language, Bus corresponds to pks, Car to auto, and Train to ciuchcia, co their order should be:
Car, Train, Bus and not Bus, Car, Train. It's just an example, my problem involves something like 10 different values.
The problem is, I can't get all the data, then perform a sort in Java, because the data is paginated. I tried to solve this problem by doing this in SQL (the data is from database view):
(CASE sample WHEN 'Car' THEN 1 WHEN 'Train' THEN 2 WHEN 'Bus' THEN 3 ELSE 0 END)
I'm sorting by number, and this solution works. However, I feel like this can be done better, and doesn't need to be modified each time I want to add something. Any help would be very appreciated.
If you can hard-code or populate the translation in the enum you can make the enum generate the query.
enum Sample {
Bus("pks"), Car("auto"), Train("ciuchcia");
private final String localName;
Sample(String localName) {
this.localName = localName;
}
private static final List<Sample> inLocalOrder = Arrays.stream(values())
.sorted((a,b) -> a.localName.compareTo(b.localName))
.collect(Collectors.toList());
public static CharSequence inLocalOrder() {
StringBuilder sb = new StringBuilder("(CASE");
int i = 1;
inLocalOrder.stream().forEach(a -> sb.append(" WHEN '"+a.name()+"' THEN "+i));
sb.append(" ELSE 0 END)");
return sb;
}
}
public void test(String[] args) {
System.out.println(Sample.inLocalOrder());
}
prints:
(CASE WHEN 'Car' THEN 1 WHEN 'Train' THEN 2 WHEN 'Bus' THEN 3 ELSE 0 END)
If the translations happen later then a minor adjustment should suffice.
First things first. Why you're using an Enum to sort stuff? I can't agree with this feature, but it's ok if you really need it.
I really appreciate #OldCurmudgeon's answer, but I would have done something different.
Instead of using the property value as the column name, I would use a method to request the correct column name (obviously I'm supposing that you don't have the entities mapped inside your code, so you're using an Enum to sort them). This way:
enum Sample {
Bus, Car, Train;
public String getColumnName() {
// GET IT FROM SOME RESOURCE OR REQUEST IT FROM ANOTHER CONTEXT OR JUST RETURN IT THE WAY IT IS
// YOU CAN USE A RESOURCE FILE TO MAP YOUR COLUMN NAME, SO IF THE ENTITY CHANGES, YOU DON'T NEED
// TO UPDATE YOUR CODE...
return "";
}
public static String getSortSQL(Map<Sample, Integer> samples) {
StringBuilder sb = new StringBuilder("(CASE");
samples.forEach((sample, number) -> addSampleNumberSQL(sb, sample, number));
return sb.append(" ELSE 0 END)").toString();
}
private static StringBuilder addSampleNumberSQL(StringBuilder sb, Sample sample, Integer number) {
return sb.append(" WHEN '").append(sample.getColumnName()).append("' THEN ").append(number);
}
}
As you can see, you can request your column name from any resource you want. But this implementation still weak because if you need to sort by any new column, you will need to add another Enum value. So I would implement something more powerfull, like a properties reader that read each property from the resource and a method that receive an String (mean the property itself) and a number (to sort by the number) so I would do something like this:
public static String getSortSQL(Map<String, Integer> properties) {
StringBuilder sb = new StringBuilder("(CASE");
properties.forEach((prop, number) -> addSampleNumberSQL(sb, prop, number));
return sb.append(" ELSE 0 END)").toString();
}
private static StringBuilder addSampleNumberSQL(StringBuilder sb, String property, Integer number) {
return sb.append(" WHEN '").append(property).append("' THEN ").append(number);
}
Hope it helps you...

Returning switch capable value based on String

Not sure how I'm going to attack this.
Basically what I have is input of varying length, one or multiple times, that will cause an action. It being from typed input, file etc.
I have no idea on by what and how to tackle this. Would it be best to have a function returning an int that correspond to an public static final int FOO = 1;, an enum, an other way?
What I have as of now is a series of if statements as in:
if (str.equals("foo") || str.equals("F")) {
blah;
} else if (str.equals("beach")) {
more blah;
}
Is this good as any, or is there a better way? Have had a peek at enum but seems like that is more to it then in e.g. C. This is probably wrong, but would it be something in the direction of this?
class Mother
{
HappyCamping() {
switch (ValInput(str)) {
case FOO: do fo; break;
case BAR: do bar; break;
case BAZ: do fo bar: break
...
}
private enum ValInput(String str)
{
FOO("foo"), BAR("bar"), BAZ("baz");
private int value;
private ValInput(String str) {
if (str.equals("blah"))
this.value = 1;
...
}
}
}
Point being having a cleaner approach and separate out the "parsing" from the main routine. What would be a good way here?
One approach would be to write a parser that returns tokens. The tokens could be represented by ints or Enums. That modularizes your code in a way you suggest you want.
The other way is to use enums.
public enum Token {
FOO("foo", "f"),
BAR("bar", "b");
private String keyword;
private String abbreviation;
private Token(String keyword, String abbreviation) {
this.keyword = keyword;
this.abbreviation = abbreviation;
}
public String getKeyword() {
return this.keyword;
}
public String getAbbreviation() {
return this.abbreviation;
}
public static Token valueOf(String s) {
for (Token token : values()) {
if (token.getKeyword().equals(s) || token.getAbbreviation().equals(s)) {
return token;
}
}
throw new IllegalArgumentException("No such keyword: " + s);
}
}
Then you can do something like:
switch (Token.valueOf(inputString)) {
case BAR : doBarStuff(); return;
case FOO : doFooStuff(); return;
}
Is this good as any, or is there a better way? Have had a peek at enum but seems like that is more to it then in e.g. C. This is probably wrong, but would it be something in the direction of this?
Then go learn how enum works. Don't avoid a feature that may solve your problem just because it has more features. Chances are your design will want to make use of Java-style enums if you want a fixed set of actions.
enum Action { CLICK("click"), CLEAR("erase"); }
etc. is a good start.
Java (I think since 6, possibly 7) also supports switch taking strings instead of integer or enum values.
Not sure that I understand the entire problem, but you can convert a string to an enum easily in Java.
If the entry strings are limited and predefined, and you want to parse it as an enum using
EnumType.valueOf("foo")
I recommend reading on Java enums, they are quite powerful compared to C enums.
In Java 7 you can use String in a switch expression. Refer to this article:
switch (str) {
case "blah":
// some action
break;
case "beach":
// another blah
break;
default:
// default action
break;
}
Your if statements seems the most logical way to tackle this problem. No need to make your life complex, just keep it simple. Any other method has trade offs and complexity.
Consider using a Map and the command pattern as shown here. You can hide all map a keyword to functionality and never have to use an if or switch.

Java enum confusion with creating a bitmask and checking permissions

I want to port this c# permission module to java, but I am confused how I can do this when I can't save the numeric value in the database and then cast it to the enumeration representation.
In c#, I create a enum like this:
public enum ArticlePermission
{
CanRead = 1,
CanWrite = 2,
CanDelete = 4,
CanMove = 16
}
I then can create a permission set like:
ArticlePermission johnsArticlePermission = ArticlePermission.CanRead | ArticlePermission.CanMove;
I then save this into the database using:
(int)johnsArticlePermission
Now I can read it from the database as an integer/long, and cast it like:
johnsArticlePermission = (ArticlePermission) dr["articlePermissions"];
And I can check permissions like:
if(johnsArticlePermission & ArticlePermission.CanRead == ArticlePermission.CanRead)
{
}
How can I do this in java?
From what I understand, in java, you can convert the enumeration into a numeric value, and then convert it back to a java enumeration.
Ideas?
What you really need here is an EnumSet, described in the API like this:
Enum sets are represented internally as bit vectors. This
representation is extremely compact and efficient. The space and time
performance of this class should be good enough to allow its use as a
high-quality, typesafe alternative to traditional int-based "bit
flags."
An enum is a class under the hood so you can add methods to it. For example,
public enum ArticlePermission
{
CanRead(1),
CanWrite(2),
CanDelete(4),
CanMove(16); // what happened to 8?
private int _val;
ArticlePermission(int val)
{
_val = val;
}
public int getValue()
{
return _val;
}
public static List<ArticlePermission> parseArticlePermissions(int val)
{
List<ArticlePermission> apList = new ArrayList<ArticlePermission>();
for (ArticlePermission ap : values())
{
if (val & ap.getValue() != 0)
apList.add(ap);
}
return apList;
}
}
parseArticlePermissions will give you a List of ArticlePermission objects from an integer value, presumably created by ORing the value of ArticlePermission objects.
Here is a more detailed explanation of EnumSet.

Loop for Enums in Java

I have some enums like this:
public enum Classification {
UNKNOWN("Unknown"),
DELETION("Deletion"),
DUPLICATION("Duplication"), ....
but some of them have like 20 members, so currently in code I deal with them with huge if/else blocks like this:
int classification= rs.getInt("classification");
if (classification == Classification.UNKNOWN.ordinal()) {
variant.setClassification(Classification.UNKNOWN);
} else if (classification == Classification.DELETION.ordinal()) {
variant.setClassification(Classification.DELETION);
( rs is from JDBC tho).
Does Java have a better way this these big if/else blocks to do what I am doing? some sorting of looping through it?
You could use Enum#values() to get all enum values in an array. The ordinal maps 1:1 to the array index. Add the following method fo your Classification enum:
public static Classification of(int ordinal) {
if (0 <= ordinal && ordinal < values().length) {
return values()[ordinal];
}
throw new IllegalArgumentException("Invalid ordinal " + ordinal);
}
and use it as follows
Classification classification = Classification.of(rs.getInt("classification"));
// ...
However, using enum's ordinal for this is not the best practice. What if some developer rearranges the enum's values or adds/removes values? Even the javadoc warns that it has usually no use for developers. Rather give each enum value a fixed identifier. You could pass it in as an additional argument of the enum constructor argument. You could even use enum's String representation for that.
UNKNOWN(1, "Unknown"),
DELETION(2, "Deletion"),
DUPLICATION(3, "Duplication"),
// ...
Then use that value for DB instead and modify the of() method to walk through them in a foreach loop:
public static Classification of(int id) {
for (Classification classification : values()) {
if (classification.id == id) {
return classification;
}
}
throw new IllegalArgumentException("Invalid id " + id);
}
If the db value is the ordinal of the Enum then:
int classification= rs.getInt("classification");
variant.setClassification(Classification.values()[classification]);
I'll leave bounds checking as an exercise for the reader.
You can loop through an enumeration’s values via the object the someEnum.values() method returns:
for (Classification clz : Classification.values()) doSomethingWith(clz);
found here
I don’t know how exactly I can help you, since i don’t know what rs.getInt(String) does.
It seems to give back an Integer representing a enum value of Classification, but why?
Use variant.setClassification(YourEnumClassHere.values()[classification]). Enum.values() returns an array of all the declared enums in that class.
Instead of storing ordinal, you can store the name and use the valueOf method to convert the String back to your Enum type.
If you willing and able to store a string representation (this is a good technique) of the ENUM in your database, see Reference from Gareth Davis in comments above. If you are unwilling and/or unable to store a string representation and must continue with an ordinal representation, I suggest that a Map is called for. Here is some example code:
public class EnumMap
{
private enum FistSounds
{
Blam, Kapow, Zowie, Biff;
private static Map<Integer, FistSounds> ordinalMap = new HashMap<Integer, FistSounds>();
static
{
ordinalMap.put(Blam.ordinal(), Blam);
ordinalMap.put(Kapow.ordinal(), Kapow);
ordinalMap.put(Zowie.ordinal(), Zowie);
ordinalMap.put(Biff.ordinal(), Biff);
}
public static final FistSounds getByOrdinal(final int enumIndex)
{
return ordinalMap.get(enumIndex);
}
}
public static void main(String[] args)
{
FistSounds fistSound;
for (int index = -1; index < 5; ++index)
{
fistSound = FistSounds.getByOrdinal(index);
System.out.print("Ordinal: ");
System.out.print(index);
System.out.print(", FistSound: ");
System.out.println(fistSound);
}
}
}
I'd recommend using a switch statement, if the logic to execute is different for each case....
do as #Gareth Davis instructs and then just have a switch statement and handle each case as required.
Enums are also eligible to be used in switch statements see here

Convert from enum ordinal to enum type

I've the enum type ReportTypeEnum that get passed between methods in all my classes but I then need to pass this on the URL so I use the ordinal method to get the int value. After I get it in my other JSP page, I need to convert it to back to an ReportTypeEnum so that I can continue passing it.
How can I convert ordinal to the ReportTypeEnum?
Using Java 6 SE.
To convert an ordinal into its enum representation you might want to do this:
ReportTypeEnum value = ReportTypeEnum.values()[ordinal];
Please notice the array bounds.
Note that every call to values() returns a newly cloned array which might impact performance in a negative way. You may want to cache the array if it's going to be called often.
Code example on how to cache values().
This answer was edited to include the feedback given inside the comments
This is almost certainly a bad idea. Certainly if the ordinal is de-facto persisted (e.g. because someone has bookmarked the URL) - it means that you must always preserve the enum ordering in future, which may not be obvious to code maintainers down the line.
Why not encode the enum using myEnumValue.name() (and decode via ReportTypeEnum.valueOf(s)) instead?
If I'm going to be using values() a lot:
enum Suit {
Hearts, Diamonds, Spades, Clubs;
public static final Suit values[] = values();
}
Meanwhile wherever.java:
Suit suit = Suit.values[ordinal];
If you want the array to be private, be my guest:
private static final Suit values[] = values();
public static Suit get(int ordinal) { return values[ordinal]; }
...
Suit suit = Suit.get(ordinal);
Mind your array bounds.
I agree with most people that using ordinal is probably a bad idea. I usually solve this problem by giving the enum a private constructor that can take for example a DB value then create a static fromDbValue function similar to the one in Jan's answer.
public enum ReportTypeEnum {
R1(1),
R2(2),
R3(3),
R4(4),
R5(5),
R6(6),
R7(7),
R8(8);
private static Logger log = LoggerFactory.getLogger(ReportEnumType.class);
private static Map<Integer, ReportTypeEnum> lookup;
private Integer dbValue;
private ReportTypeEnum(Integer dbValue) {
this.dbValue = dbValue;
}
static {
try {
ReportTypeEnum[] vals = ReportTypeEnum.values();
lookup = new HashMap<Integer, ReportTypeEnum>(vals.length);
for (ReportTypeEnum rpt: vals)
lookup.put(rpt.getDbValue(), rpt);
}
catch (Exception e) {
// Careful, if any exception is thrown out of a static block, the class
// won't be initialized
log.error("Unexpected exception initializing " + ReportTypeEnum.class, e);
}
}
public static ReportTypeEnum fromDbValue(Integer dbValue) {
return lookup.get(dbValue);
}
public Integer getDbValue() {
return this.dbValue;
}
}
Now you can change the order without changing the lookup and vice versa.
You could use a static lookup table:
public enum Suit {
spades, hearts, diamonds, clubs;
private static final Map<Integer, Suit> lookup = new HashMap<Integer, Suit>();
static {
int ordinal = 0;
for (Suit suit : EnumSet.allOf(Suit.class)) {
lookup.put(ordinal, suit);
ordinal+= 1;
}
}
public Suit fromOrdinal(int ordinal) {
return lookup.get(ordinal);
}
}
This is what I use. I make no pretense that it's far less "efficient" than the simpler solutions above. What it does do is provide a much clearer exception message than "ArrayIndexOutOfBounds" when an invalid ordinal value is used in the solution above.
It utilizes the fact that EnumSet javadoc specifies the iterator returns elements in their natural order. There's an assert if that's not correct.
The JUnit4 Test demonstrates how it's used.
/**
* convert ordinal to Enum
* #param clzz may not be null
* #param ordinal
* #return e with e.ordinal( ) == ordinal
* #throws IllegalArgumentException if ordinal out of range
*/
public static <E extends Enum<E> > E lookupEnum(Class<E> clzz, int ordinal) {
EnumSet<E> set = EnumSet.allOf(clzz);
if (ordinal < set.size()) {
Iterator<E> iter = set.iterator();
for (int i = 0; i < ordinal; i++) {
iter.next();
}
E rval = iter.next();
assert(rval.ordinal() == ordinal);
return rval;
}
throw new IllegalArgumentException("Invalid value " + ordinal + " for " + clzz.getName( ) + ", must be < " + set.size());
}
#Test
public void lookupTest( ) {
java.util.concurrent.TimeUnit tu = lookupEnum(TimeUnit.class, 3);
System.out.println(tu);
}
Safety first (with Kotlin):
// Default to null
EnumName.values().getOrNull(ordinal)
// Default to a value
EnumName.values().getOrElse(ordinal) { EnumName.MyValue }
This is what I do on Android with Proguard:
public enum SomeStatus {
UNINITIALIZED, STATUS_1, RESERVED_1, STATUS_2, RESERVED_2, STATUS_3;//do not change order
private static SomeStatus[] values = null;
public static SomeStatus fromInteger(int i) {
if(SomeStatus.values == null) {
SomeStatus.values = SomeStatus.values();
}
if (i < 0) return SomeStatus.values[0];
if (i >= SomeStatus.values.length) return SomeStatus.values[0];
return SomeStatus.values[i];
}
}
it's short and I don't need to worry about having an exception in Proguard
You can define a simple method like:
public enum Alphabet{
A,B,C,D;
public static Alphabet get(int index){
return Alphabet.values()[index];
}
}
And use it like:
System.out.println(Alphabet.get(2));
public enum Suit implements java.io.Serializable, Comparable<Suit>{
spades, hearts, diamonds, clubs;
private static final Suit [] lookup = Suit.values();
public Suit fromOrdinal(int ordinal) {
if(ordinal< 1 || ordinal> 3) return null;
return lookup[value-1];
}
}
the test class
public class MainTest {
public static void main(String[] args) {
Suit d3 = Suit.diamonds;
Suit d3Test = Suit.fromOrdinal(2);
if(d3.equals(d3Test)){
System.out.println("Susses");
}else System.out.println("Fails");
}
}
I appreciate that you share with us if you have a more efficient code, My enum is huge and constantly called thousands of times.
So one way is to doExampleEnum valueOfOrdinal = ExampleEnum.values()[ordinal]; which works and its easy, however,
as mentioned before, ExampleEnum.values() returns a new cloned array for every call. That can be unnecessarily expensive. We can solve that by caching the array like so ExampleEnum[] values = values(). It is also "dangerous" to allow our cached array to be modified. Someone could write ExampleEnum.values[0] = ExampleEnum.type2; So I would make it private with an accessor method that does not do extra copying.
private enum ExampleEnum{
type0, type1, type2, type3;
private static final ExampleEnum[] values = values();
public static ExampleEnum value(int ord) {
return values[ord];
}
}
You would use ExampleEnum.value(ordinal) to get the enum value associated with ordinal
There is an Easy and Bad way and there is a fairly easy and right way.
First, the easy and bad (those are usually very popular). Enum class method returns an array of all available instances via the values() method and you can access the enum object via array index.
RenderingMode mode = RenderingMode.values()[index];
//Enum Class somewhere else
public enum RenderingMode
{
PLAYING,
PREVIEW,
VIEW_SOLUTION;
}
//RenderingMode.values()[0] will return RenderingMode.PLAYING
//RenderingMode.values()[1] will return RenderingMode.PREVIEW
//Why this is bad? Because it is linked to order of declaration.
//If you later changed the order here, it will impact all your existing logic around this.
public enum RenderingMode
{
PREVIEW,
VIEW_SOLUTION,
PLAYING;
}
//Now
//RenderingMode.values()[0] will return RenderingMode.PREVIEW
//RenderingMode.values()[1] will return RenderingMode.VIEW_SOLUTION
Here is the right way to do it.
Create a static method fromInt in your enum class.
public enum RenderingMode
{
PLAYING,
PREVIEW,
VIEW_SOLUTION;
public static RenderingModefromInt(int index)
{
//this is independent of order of declaration
switch (index)
{
case 0: return PLAYING;
case 1: return PREVIEW;
case 2: return VIEW_SOLUTION;
}
//Consider throwing Exception here
return null;
}
}
public enum Status {
STATUS_1, STATUS_2, STATUS_3, STATUS_4;
public static Status getStatusByOrdinal(int ordinal) {
for (Status status : values()) {
if (status.ordinal() == ordinal) {
return status;
}
}
return STATUS_1;
}
}
In this way you can not depend on compile-time generics resolution(so having an enum class instance you can create whenever enum you want, even those types created with Class.forMame)
public Object getInstance(Class enumClazz, int ordinal) throws Exception {
Object[] allEnums = enumClazz.getDeclaredMethod("values", Object[].class).invoke(null, null);
return allEnums[ordinal];
}
Every enum has name(), which gives a string with the name of enum member.
Given enum Suit{Heart, Spade, Club, Diamond}, Suit.Heart.name() will give Heart.
Every enum has a valueOf() method, which takes an enum type and a string, to perform the reverse operation:
Enum.valueOf(Suit.class, "Heart") returns Suit.Heart.
Why anyone would use ordinals is beyond me. It may be nanoseconds faster, but it is not safe, if the enum members change, as another developer may not be aware some code is relying on ordinal values (especially in the JSP page cited in the question, network and database overhead completely dominates the time, not using an integer over a string).

Categories