Java generics and numeric types - java

I'd like to create a generic method which does effectively this:
class MyClass {
static <T extends Number> T sloppyParseNumber(String str) {
try {
return T.valueOf(str);
} catch (Exception e) {
return (T)0;
}
}
}
Now above does not compile for two reasons: there's no Number.valueOf() method and 0 can't be cast to T.
Example usage:
String value = "0.00000001";
System.out.println("Double: " + MyClass.<Double>sloppyParseNumber(value));
System.out.println("Float: " + MyClass.<Float>sloppyParseNumber(value));
double d = MyClass.sloppyParseNumber(value);
float f = MyClass.sloppyParseNumber(value);
Is implementing above generic method possible with Java? If yes, how? If no, what's a good alternative approach?
Edit: there seems to be a few possible duplicates, but I did not find one, which covers exactly this. I'm hoping there's some trick to pull, which would allow these two operations: parse string to a Number subclass, and return 0 value for a Number subclass.

I agree 100% with TofuBeer. But in case you wish to avoid verbosity for time sake, this should also do:
static <T extends Number> T sloppyParseNumber(String str,Class<T> clas) {
if (clas == null) throw new NullPointerException("clas is null");
try {
if(clas.equals(Integer.class)) {
return (T) Integer.valueOf(str);
}
else if(clas.equals(Double.class)) {
return (T) Double.valueOf(str);
}
//so on
catch(NumberFormatException|NullPointerException ex) {
// force call with valid arguments
return sloppyParseNumber("0", clas);
}
throw new IllegalArgumentException("Invalid clas " + clas);
}
But purely from T, you cannot get the type at runtime.

Java generics only provide compile time checks and the type information is pretty much thrown away after compilation. So the statement T.valueOf isn't possible in Java. The solution is to go the verbose way as already mentioned in the comments. Also, is there any reason why you want to do MyClass.<Double>sloppyParseNumber(value) but not MyClass.sloppyParseDouble(value) since you are anyway specifying the type at compile time?

Static methods are bound by the type, since the type is, at best, Number and Number doesn't have a valueOf method what you are after isn't going to work.
The easiest way is to just make a number of static methods like sloppyParseInt, sloppyParseFloat, etc...
You could do something like this, not sure I like it, and can probably be improved on:
public class Main
{
private static final Map<Class<? extends Number>, NumberConverter> CONVERTERS;
static
{
CONVERTERS = new HashMap<>();
CONVERTERS.put(Integer.class, new IntegerConverter());
}
public static void main(String[] args)
{
Number valueA;
Number valueB;
valueA = CONVERTERS.get(Integer.class).convert("42");
valueB = CONVERTERS.get(Integer.class).convert("Hello, World!");
System.out.println(valueA);
System.out.println(valueB);
}
}
interface NumberConverter<T extends Number>
{
T convert(String str);
}
class IntegerConverter
implements NumberConverter<Integer>
{
#Override
public Integer convert(String str)
{
try
{
return Integer.valueOf(str);
}
catch (NumberFormatException ex)
{
return 0;
}
}
}

So, I decided on an alternative approach:
static String trimTo0(String str) {
if (str == null) return "0";
str = str.trim();
if (str.isEmpty()) return "0";
return str;
}
Usage:
String value = null;
System.out println("Double value: " + Double.parseDouble(trimTo0(value)));
Note that this is more limited than the method in the question, this does not convert invalid, non-numeric strings to "0". Doing that fully would require two separate methods, one supporting decimal point and another just supporting integers.

You can try this:
private <T> T convertToType(Class<T> clazz,String str) throws Exception {
return clazz.getConstructor(String.class).newInstance(str);
}
Here you need to consider that the Type must have a constructor with a String parameter.

Related

Java parsing from string to numeric but infer type

I am trying to write a generic method converting a string to number. Which API can I use to finish this.
private <T extends Number> T parseFromString(String str) {
// convert str to number
}
Then call :
parseFromString<Double>("120.0");
parseFromString<Integer>("11");
No need to use generic, I would just use :
private static Number parseFromString(String str) throws NumberFormatException {
if (str.matches("\\d+")) {
return Integer.valueOf(str);
} else if (str.matches("[-+]?[0-9]*\\.?[0-9]+")) {
return Double.valueOf(str);
}
throw new NumberFormatException("Number not correct");
}
Outputs
System.out.println(parseFromString("11")); // 11
System.out.println(parseFromString("112.3")); // 112.3
System.out.println(parseFromString("some not correct strings")); // Number not correct
Or as #shmosel mentioned in his comment, you can just use :
private static Number parseFromString(String str) throws ParseException {
return NumberFormat.getInstance().parse(str);
}
In this solution you may lose precision, so it may required to use locale, like so :
private static Number parseFromString(String str) throws ParseException {
return NumberFormat.getInstance(Locale.CANADA).parse(str);
}

Can Optional be used to as alternative to catch ConversionException

How to refactor the following code of reading properties file, so that it returns int, double or String depending on the read value?
public static <T> T readFromConfig(String keyName) {
PropertiesConfiguration config = new PropertiesConfiguration();
String propertiesFilePath = "src/main/resources/application.properties";
try {
config.load(propertiesFilePath);
try {
Integer value = config.getInt(keyName);
return (T) value;
} catch (ConversionException notInteger) {
try {
Double value = config.getDouble(keyName);
return (T) value;
} catch (ConversionException notDouble) {
return (T) config.getString(keyName);
}
}
} catch (ConfigurationException e) {
logger.warn("Could not parse " + propertiesFilePath);
return (T) "";
}
}
As the author figured himself: Optional<> isn't an option here, because, as the other answer shows: it would result in returning Optional<Object> which gives even less type information.
But honestly, from a clean code perspective, even the idea of
public static <T> T readFromConfig(String keyName) {
is kinda flawed. What does that method buy? Nothing. Because the caller says: I expect an Integer to come back, but you push back a Double or even String. You see, the compiler gets told "the method should return Integer, or Double, ...", and then it sees: "yes, possible". But that is totally decoupled from what happens at runtime.
If you go:
Integer intVal = readFromConfig("keyPointingToDoubleValue");
the compiler will not complain. Because it sees: you want an Integer; and hey, the method can return an Integer.
At runtime? When the value is retrieved, and isn't an Integer, a Double or String is returned. No idea what will happen here (class cast exception, or maybe some stack violation). But it should not work at runtime.
So, the real solution goes like this:
Either you have multiple methods, such as:
public static Integer readIntegerFromConfig(String keyName) throws SomeException ...
public static Integer readIntegerFromConfig(String keyName, Integer Default) throws SomeException ...
Or maybe:
public static Object readFromConfig(String keyName) {
or
public static <T> T readFromConfig(String keyName, T default)
In other words: you want an API that allows users of it to really say what they want, and always give them what they want. Or you totally avoid distinct types on that level, and return Strings, and have the client code make conversions.
Your current approach, as said: buys you nothing, at the cost of a misleading, complicated API.
Here is what I can suggest you also this is a clear violation of Single Responsibility Principle (SRP) as it tries to convert to three different types which should be avoided for cleaner code :
public static Optional<Object> readFromConfig(String keyName) {
PropertiesConfiguration config = new PropertiesConfiguration();
String propertiesFilePath = "src/main/resources/opf.properties";
try {
config.load(propertiesFilePath);
return Stream.<Supplier<Optional>>of(
() -> Optional.of(config.getInt(keyName)),
() -> Optional.of(config.getDouble(keyName)),
() -> Optional.of(config.getString(keyName)))
.map(Supplier::get)
.filter(Optional::isPresent)
.map(Optional::get)
.findFirst();
} catch (Exception e) {
return Optional.empty();
}
}
So, that's the end of deiscussion.
The answer for question "Can Optional be used to as alternative to catch ConversionException?" is NO

How do I return a Number object of the same concrete type as one passed in?

I have the following incomplete class. It implements a method that takes any Number object as a parameter and constrains it to a limit stored in a long and then returns the original value or the constrained value. However, the returned constrained value must be of the same concrete type as the input parameter.
public class Max implements Constraint {
long max;
public Number constrain(Number n) {
if (n.longValue() <= max) {
return n;
}
// return a number of the type passed in with value max
}
}
There are other questions about creating an object of the same type as another, but the answers assume a no-arg constructor is available and this is not the case for the numeric types.
I have played with:
n.getClass().getConstructor(new Class<?>[] { n.getClass() }).newInstance(max);
but I still have issues about passing in the right parameter even here. I am back to square one. In any case, it isn't very elegant.
I know I can do it with a lot of if statements, but I am looking for something smarter.
Because the constuctor of SubClasses of Number takes primitives as parameter, you cannot look for the constructore that has the Wrapper Class as parameter
The constructor that they all have, is the String one
long max;
public Number constrain(Number n) {
if (n.longValue() <= max)
try{
return n.getClass()
.getConstructor(String.class)
.newInstance(String.valueOf(max));
}catch(Exception ex){ex.printStackTrace();}
return n;
}
public static void main(String[]args){
Max m = new Max();
m.max = 10;
System.out.println(m.constrain(new Double(25)).getClass()); // class java.lang.Double
System.out.println(m.constrain((int) 18).getClass()); // class java.lang.Integer
}
Working DEMO
with Java 5 or hogher you can use a generic in your methods like this
package test;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import org.junit.Assert;
public class Max {
Number max;
public <T extends Number> T constrain(T n) {
if (n.floatValue() <= max.floatValue()) {
return n;
} else {
return castTo(max, n.getClass());
}
}
#SuppressWarnings("unchecked")
private <T extends Number> T castTo(Number max2, Class<? extends Number> class1) {
if (class1.equals(AtomicInteger.class)) {
return (T) new AtomicInteger(max2.intValue());
} else if (class1.equals(AtomicLong.class)) {
return (T) new AtomicLong(max2.longValue());
// these case are dangerous to handle
} else if (class1.equals(BigDecimal.class)) {
return (T) BigDecimal.valueOf(max2.doubleValue());
} else if (class1.equals(BigInteger.class)) {
return (T) BigInteger.valueOf(max2.longValue());
// Std Case
} else if (class1.equals(Byte.class)) {
return (T) (Byte) max2.byteValue();
} else if (class1.equals(Double.class)) {
return (T) (Double) max2.doubleValue();
} else if (class1.equals(Float.class)) {
return (T) (Float) max2.floatValue();
} else if (class1.equals(Integer.class)) {
return (T) (Integer) max2.intValue();
} else if (class1.equals(Long.class)) {
return (T) (Long) max2.longValue();
} else if (class1.equals(Short.class)) {
return (T) (Short) max2.shortValue();
} else {
throw new IllegalArgumentException("Can't handle this kind of Number : " + class1.getName());
}
}
public static void main(String[] args) {
Max max = new Max();
max.max = 32;
Integer constrain = max.constrain(33);
Assert.assertEquals(Integer.class, constrain.getClass());
Assert.assertEquals(max.max, constrain);
Double constrain2 = max.constrain(33d);
Assert.assertEquals(Double.class, constrain2.getClass());
Assert.assertEquals(max.max.doubleValue(), constrain2, 0);
Float constrain3 = max.constrain(33f);
Assert.assertEquals(Float.class, constrain3.getClass());
Assert.assertEquals(max.max.floatValue(), constrain3, 0);
Short constrain4 = max.constrain((short) 33);
Assert.assertEquals(Short.class, constrain4.getClass());
Assert.assertEquals(max.max.shortValue(), constrain4, 0);
Byte constrain5 = max.constrain((byte) 33);
Assert.assertEquals(Byte.class, constrain5.getClass());
Assert.assertEquals(max.max.byteValue(), constrain5, 0);
Long constrain6 = max.constrain(33l);
Assert.assertEquals(Long.class, constrain6.getClass());
Assert.assertEquals(max.max.longValue(), constrain6, 0);
BigDecimal constrain7 = max.constrain(BigDecimal.valueOf(33));
Assert.assertEquals(BigDecimal.class, constrain7.getClass());
BigInteger constrain8 = max.constrain(BigInteger.valueOf(33));
Assert.assertEquals(BigInteger.class, constrain8.getClass());
AtomicInteger constrain9 = max.constrain(new AtomicInteger(33));
Assert.assertEquals(AtomicInteger.class, constrain9.getClass());
AtomicLong constrain10 = max.constrain(new AtomicLong(33));
Assert.assertEquals(AtomicLong.class, constrain10.getClass());
}
}
but inside your code to construct all child of number there no common constructor the safest way is to reduce the case you want handle here i didn't handle all Striped64 children
I discovered:
import org.apache.commons.beanutils.ConvertUtils;
...
return (Number)ConvertUtils.convert(max, n.getClass());
I haven't looked at the source, but I doubt it is very clever inside. I believe it just hosts a collection of type converters.
So this is an alternative - not better than the other answers, but at least it is concise.
Edit - v3 - without String.
If you only talk about members of Numbers that allows primitive type as the input of constructor like Float/Double/Integer/Long/..., the following could work:
//Number n is valid someInput;
//Note this only works for Classes that take a single numeric value as input
Class type = (Class) n.getClass().getDeclaredField("TYPE").get(n);
return n.getClass().getConstructor(type).newInstance(max)
Things like BigInteger will not work with this one.
Edit - v2
It seems like, for primitive types n, if the "Number n" is replaced by different signatures and by using Integer.TYPE (or Float.TYPE and etc.) you might pass in the 'int' as parameters of getConstructor. You may use n.TYPE here (but as a reminder TYPE is the class member, and it may pop some warning).
n.getClass().getConstructor(n.TYPE).newInstance(max);
Still, as #azro pointed out: if you insist not using string and want it smart, you still need branches and it could be nastier: you need to consider all subclasses of Number, including BigInteger.
True, casting it to string is nasty, but otherwise, you may need to wrap each subclass of Number with an extra class that allows the non-primitive type as args of the constructor. I barely think if-statements is nastier.
Original Answer
I am not very familiar with Reflection.
But a major problem here is the constructor of Numbers are either String or primitive types like 'int', and you cannot really utilize 'int' as the input of getConstructor.
at least, the following may work.
//assume n is some Number object.
n.getClass().getConstructor(String.class).newInstance(max.toString());
This works as classes like Float/Integer/BigInt.../ have constructors that take String as the input.

Storing EnumSet in a database?

So in C++/C# you can create flags enums to hold multiple values, and storing a single meaningful integer in the database is, of course, trivial.
In Java you have EnumSets, which appear to be quite a nice way to pass enums around in memory, but how do you output the combined EnumSet to an integer for storage? Is there another way to approach this?
Storing the ordinal as a representation of the EnumSet is not a good idea. The ordinal numbers depend on the order of the definition in the Enum class (a related discussion is here). Your database may be easily broken by a refactoring that changes the order of Enum values or introduces new ones in the middle.
You have to introduce a stable representation of individual enum values. These can be int values again and represented in the proposed way for the EnumSet.
Your Enums can implement interfaces so the stable represenation can be directly in the enum value (adapted from Adamski):
interface Stable{
int getStableId();
}
public enum X implements Stable {
A(1), B(2);
private int stableId;
X(int id){
this.stableId = id;
}
#Override public int getStableId() {
return stableId;
}
}
adapted from Adamski's code:
public <E extends Stable> int encode(EnumSet<E> set) {
int ret = 0;
for (E val : set) {
ret |= (1 << val.getStableId());
}
return ret;
}
Providing your enum fits into an int (i.e. there are <= 32 values) I would roll my own implementation by using each enum's ordinal value; e.g.
public <E extends Enum<E>> int encode(EnumSet<E> set) {
int ret = 0;
for (E val : set) {
// Bitwise-OR each ordinal value together to encode as single int.
ret |= (1 << val.ordinal());
}
return ret;
}
public <E extends Enum<E>> EnumSet<E> decode(int encoded, Class<E> enumKlazz) {
// First populate a look-up map of ordinal to Enum value.
// This is fairly disgusting: Anyone know of a better approach?
Map<Integer, E> ordinalMap = new HashMap<Integer, E>();
for (E val : EnumSet.allOf(enumKlazz)) {
ordinalMap.put(val.ordinal(), val);
}
EnumSet<E> ret= EnumSet.noneOf(enumKlazz);
int ordinal = 0;
// Now loop over encoded value by analysing each bit independently.
// If the bit is set, determine which ordinal that corresponds to
// (by also maintaining an ordinal counter) and use this to retrieve
// the correct value from the look-up map.
for (int i=1; i!=0; i <<= 1) {
if ((i & encoded) != 0) {
ret.add(ordinalMap.get(ordinal));
}
++ordinal;
}
return ret;
}
Disclaimer: I haven't tested this!
EDIT
As Thomas mentions in the comments the ordinal numbers are unstable in that any change to your enum definition within your code will render the encodings in your database corrupt (e.g. if you insert a new enum value in the middle of your existing definition). My approach to solving this problem is to define an "Enum" table per enumeration, containing a numerical ID (not the ordinal) and the String enum value. When my Java application starts, the first thing the DAO layer does is to read each Enum table into memory and:
Verify that all String enum values in the database match the Java definition.
Initialise a Bi-directional map of ID to enum and vice-versa, which I then use whenever I persist an enum (In other words, all "data" tables reference the database-specific Enum ID, rather than store the String value explicitly).
This is much cleaner / more robust IMHO than the ordinal approach I describe above.
It struck me as a surprise that nobody was suggesting a well-maintained library instead of writing your own. The above answer is spot on and educational but it just encourages people to copy and paste code around (then mostly forget the credits).
Here's my 2 cents:
EnumSet<YourEnum> mySet = EnumSet.of(YourEnum.FIRST);
long vector = EnumUtils.generateBitVector(YourEnum.class, mySet);
EnumSet<YourEnum> sameSet = EnumUtils.processBitVector(YourEnum.class, vector);
See https://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/EnumUtils.html
// From Adamski's answer
public static <E extends Enum<E>> int encode(EnumSet<E> set) {
int ret = 0;
for (E val : set) {
ret |= 1 << val.ordinal();
}
return ret;
}
#SuppressWarnings("unchecked")
private static <E extends Enum<E>> EnumSet<E> decode(int code,
Class<E> enumType) {
try {
E[] values = (E[]) enumType.getMethod("values").invoke(null);
EnumSet<E> result = EnumSet.noneOf(enumType);
while (code != 0) {
int ordinal = Integer.numberOfTrailingZeros(code);
code ^= Integer.lowestOneBit(code);
result.add(values[ordinal]);
}
return result;
} catch (IllegalAccessException ex) {
// Shouldn't happen
throw new RuntimeException(ex);
} catch (InvocationTargetException ex) {
// Probably a NullPointerException, caused by calling this method
// from within E's initializer.
throw (RuntimeException) ex.getCause();
} catch (NoSuchMethodException ex) {
// Shouldn't happen
throw new RuntimeException(ex);
}
}
If you look in the source for RegularEnumSet, which is the implementation for Enum's <= 64 members, you will see that it contains:
/**
* Bit vector representation of this set. The 2^k bit indicates the
* presence of universe[k] in this set.
*/
private long elements = 0L;
elements is a bit-mask where the bit positions equal the enum ordinals, which is exactly what you need. However this attribute is not made availlable through a getter or setter as that would not match the equivalent accessors for the JumboEnumSet.
It is not one of the nicest solutions, but if simplicity and speed is what you are after, you could create 2 static utility methods that retrieve and set the elements attribute using reflection.
For me, I would probably just setup a constants class holding the enum values as integer constants where I can be sure which enum gets assigned what bit.
EnumSet implements Serializable, but there's a lot of overhead if you use that (it is written as an array of IDs, not a BitSet as you might expect, plus the object stream header.)
This is an old post that I found helpful, but with Java 8 or newer I've adapted the solution posted by #finnw into this interface:
public interface BitMaskable {
int getBitMaskOrdinal();
static int bitMaskValue(Set<? extends BitMaskable> set) {
int mask = 0;
for (BitMaskable val : set) {
mask |= (1 << val.getBitMaskOrdinal());
}
return mask;
}
static <E extends Enum<E> & BitMaskable> Set<E> valueOfBitMask(int mask, Class<E> enumType) {
E[] values = enumType.getEnumConstants();
EnumSet<E> result = EnumSet.noneOf(enumType);
Map<Integer, E> ordinalCache = null;
while (mask != 0) {
int ordinal = Integer.numberOfTrailingZeros(mask);
mask ^= Integer.lowestOneBit(mask);
E value = null;
if (ordinalCache != null) {
value = ordinalCache.get(ordinal);
}
if (value == null) {
for (E e : values) {
if (e.getBitMaskOrdinal() == ordinal) {
value = e;
break;
}
// if there are more values to decode and e has a higher
// ordinal than what we've seen, cache that for later
if (mask != 0 && e.getBitMaskOrdinal() > ordinal) {
if (ordinalCache == null) {
ordinalCache = new HashMap<>(values.length);
}
ordinalCache.put(e.getBitMaskOrdinal(), e);
}
}
}
if (value != null) {
result.add(value);
}
}
return result;
}
}
Usage for an enum like this (note the bmOrdinal values are out-of-order from the built-in enum ordinal values):
public enum BitMaskEnum implements BitMaskable {
A(0),
B(2),
C(1),
D(3);
private int bmOrdinal;
private BitMaskEnum(int bmOrdinal) {
this.bmOrdinal = bmOrdinal;
}
#Override
public int getBitMaskOrdinal() {
return bmOrdinal;
}
}
is then along these lines:
// encode as bit mask; result == 5
int result = BitMaskable.bitMaskValue(EnumSet.of(BitMaskEnum.A, BitMaskEnum.B));
// decode into set; result contains A & B
Set<BitMaskEnum> result = BitMaskable.valueOfBitMask(5, BitMaskEnum.class);
With the methods given in the answers it is possible to convert a integer to an EnumSet and vice versa. But I found that this is often error prone. Especially when you get negative values as java only has signed int and long. So if you plan to do such conversions on all sets of enums you might want to use a data structure that already supports this. I have created such a data structure, that can be used just like a BitSet or an EnumSet, but it also has methods such as toLong() and toBitSet(). Note that this requires Java 8 or newer.
Here's the link: http://claude-martin.ch/enumbitset/
Without going into the debate about pros and cons of ordinal values in the database - I posted a possible answer to the given question here:
JPA map collection of Enums
The idea is to create a new PersistentEnumSet which uses the implementation of java.util.RegularEnumSet, but offers the elements bitmask to JPA.
That one can than be used in an embeddable:
#Embeddable
public class InterestsSet extends PersistentEnumSet<InterestsEnum> {
public InterestsSet() {
super(InterestsEnum.class);
}
}
And that set is used in the entity:
#Entity
public class MyEntity {
// ...
#Embedded
private InterestsSet interests = new InterestsSet();
}
For further comments see my answer over there.
I have done some changes on finnw's code, so it works with enumerations having up to 64 items.
// From Adamski's answer
public static <E extends Enum<E>> long encode(EnumSet<E> set) {
long ret = 0;
for (E val : set) {
ret |= 1L << val.ordinal();
}
return ret;
}
#SuppressWarnings("unchecked")
public static <E extends Enum<E>> EnumSet<E> decode(long code,
Class<E> enumType) {
try {
E[] values = (E[]) enumType.getMethod("values").invoke(null);
EnumSet<E> result = EnumSet.noneOf(enumType);
while (code != 0) {
int ordinal = Long.numberOfTrailingZeros(code);
code ^= Long.lowestOneBit(code);
result.add(values[ordinal]);
}
return result;
} catch (IllegalAccessException ex) {
// Shouldn't happen
throw new RuntimeException(ex);
} catch (InvocationTargetException ex) {
// Probably a NullPointerException, caused by calling this method
// from within E's initializer.
throw (RuntimeException) ex.getCause();
} catch (NoSuchMethodException ex) {
// Shouldn't happen
throw new RuntimeException(ex);
}
}

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