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);
}
}
Related
I want to implement storing of enabled or disabled features into database row. When some String value is received from them the network I would like to compare it into ENUM.
ENUM:
public enum TerminalConfigurationFeatureBitString {
Authorize("authorize", 0), // index 0 in bit string
Authorize3d("authorize3d", 1), // index 1 in bit String
Sale("sale", 2), // index 2 in bit String
Sale3d("sale3d", 3), // index 3 in bit String
}
Map<TerminalConfigurationFeatureBitString, Boolean> featureMaps =
config.initFromDatabaseValue(optsFromDatabase);
featureMaps.get(transaction.transactionType);
The best way is to use featureMaps.get(TerminalConfigurationFeatureBitString.Sale);
But I don't know the incoming string what would be.
Now I get warning Unlikely argument type String for get(Object) on a Map<TerminalConfigurationFeatureBitString,Boolean>
Is there any other way to make a query into the ENUM without knowing the key?
In cases like these, I often find myself adding a static method getByX which does a lookup based upon a property of the enum:
public enum BitString {
//...
public static Optional<BitString> getByTransactionType(String transactionType)
{
return Arrays.stream(values())
.filter(x -> x.transactionType.equals(transactionType))
.findFirst();
}
}
Usage:
enum TransactionStatus
{
ENABLED, NOT_ENABLED, NOT_SUPPORTED
}
TransactionStatus status = BitString.getBygetByTransactionType(transaction.transactionType)
.map(bitString -> featureMaps.get(bitString))
.map(enabled -> enabled ? TransactionStatus.ENABLED : TransactionStatus.NOT_ENABLED)
.orElse(TransactionStatus.NOT_SUPPORTED);
Similar to #Michael's answer, you can just generate a static lookup map inside your enum which maps an enums transaction type to the actual enum:
private static final Map<String, TerminalConfigurationFeatureBitString> TRANSACTION_TYPE_TO_ENUM =
Arrays.stream(values()).collect(Collectors.toMap(
TerminalConfigurationFeatureBitString::getTransactionType,
Function.identity()
);
And then have a lookup method, also inside the enum:
public static TerminalConfigurationFeatureBitString getByTransactionType(String transactionType) {
TerminalConfigurationFeatureBitString bitString = TRANSACTION_TYPE_TO_ENUM.get(transactionType);
if(bitString == null) throw new NoSuchElementException(transactionType);
return bitString;
}
This in a way more performant than the mentioned answer, because the Map is created the first time the enum is loaded (So when it is the first time referenced). And thus the iteration happens only once. Also Maps have a rather fast lookup time so you could say that getting an enum this way works O(1) (when ignoring the initial computation time of O(n))
You can extend your enum with extra static method which will try to convert given String on enum item:
enum TerminalConfigurationFeatureBitString {
Authorize("authorize", 0), // index 0 in bit string
Authorize3d("authorize3d", 1), // index 1 in bit String
Sale("sale", 2), // index 2 in bit String
Sale3d("sale3d", 3); // index 3 in bit String
private final String value;
private final int index;
TerminalConfigurationFeatureBitString(String value, int index) {
this.value = value;
this.index = index;
}
public String getValue() {
return value;
}
public int getIndex() {
return index;
}
public static Optional<TerminalConfigurationFeatureBitString> fromValue(String value) {
for (TerminalConfigurationFeatureBitString item : values()) {
if (item.value.equals(value)) {
return Optional.of(item);
}
}
return Optional.empty();
}
}
In case option is not found, return Optional.empty(). If feature is not present it means String representation does not represent any feature. Usage:
public void test() {
EnumMap<TerminalConfigurationFeatureBitString, Boolean> featureMaps = new EnumMap<>(
TerminalConfigurationFeatureBitString.class);
Optional<TerminalConfigurationFeatureBitString> feature = TerminalConfigurationFeatureBitString.fromValue("authorize");
if (!feature.isPresent()) {
System.out.println("Feature is not foudn!");
} else {
Boolean authorize = featureMaps.get(feature.get());
if (authorize != null && authorize) {
System.out.println("Feature is enabled!");
} else {
System.out.println("Feature is disabled!");
}
}
}
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.
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.
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.
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).