Java: not-void methods as map values - java

I have some code like this:
public class A {
private final Map<String, Runnable> map = new HashMap<>();
public A() {
map.put("a", () -> a());
map.put("b", () -> b());
}
public int a() {
return 1;
}
public int b() {
return 2;
}
public int c(String s) {
// map.get(s).run(); <= returns void, but
// I need the result of the
// function paired to the string.
// What TODO?
}
}
I have not-void functions (a(), b()) as values of a map, paired to Strings. I need to run the functions and get the result of the functions, and return it in the function c(). The run() function returns void, so I can't get the value from it. Is there any way to do this?

What you want to do here is to return an int value from the method. For that, you can't use a Runnable as run() doesn't return a value.
But you can use an IntSupplier, which is a functional interface representing a function supplying an int value. Its functional method getAsInt is used to return the value.
public class A {
private final Map<String, IntSupplier> map = new HashMap<>();
public A() {
map.put("a", () -> a()); // or use the method-reference this::a
map.put("b", () -> b()); // or use the method-reference this::b
}
public int a() {
return 1;
}
public int b() {
return 2;
}
public int c(String s) {
return map.get(s).getAsInt();
}
}
Additionally, if you don't want to return a primitive but an object MyObject, you can use the Supplier<MyObject> functional interface (or Callable<MyObject> if the method to call can throw a checked exception).

The fact that lambdas are new does not mean they are necessary for every (perhaps any) solution. Consider this tried-and-true java 5 feature (a little something called enumeration objects).
public class Enumery
{
private static enum Stuffs
{
a(1),
b(2);
Stuffs(final int value)
{
this.value = value;
}
public int kapow()
{
return value;
}
final int value;
}
public int thing(final String stuffsName)
{
final int returnValue;
final Stuffs theStuffs;
theStuffs = Stuffs.valueOf(stuffsName);
returnValue = theStuffs.kapow();
return returnValue;
}
}

Related

Java: Return array of functions

I have an array of methods which can be called and need a boolean as a parameter. I have tried this:
public class Example {
public Function<Boolean, Integer> getFunctions(boolean t) {
return new Function[] {
this::magicNumber
};
}
public int magicNumber(boolean t) {
return (t) ? new Random().nextInt(11) : 0;
}
}
But then the compiler returns an error message with the message
Incompatible types: invalid method reference
Incompatible types: Object cannot be converted to boolean
The example above however can work by storing the Function in a variable and returning that, however I don't find this clean code and it's redundant.
public class Example {
public Function<Boolean, Integer> getFunctions(boolean t) {
Function<Boolean, Integer> f = this::magicNumber;
return new Function[] {
f
};
}
public int magicNumber(boolean t) {
return (t) ? new Random().nextInt(11) : 0;
}
}
Is there any way to shorten the code above like in the example in the beginning?
EDIT
As a commenter requested, I will give a short example of how I used Supplier in a previous project. I return them in an array to return objects. The problem is that this project depends on having a parameter.
public Supplier<T>[] getRecipes()
{
return new Supplier[] {
this::anchovyRule,
this::codRule,
this::herringRule,
this::lobsterRule,
this::mackerelRule,
this::pikeRule,
this::salmonRule,
this::sardineRule,
this::shrimpRule,
this::troutRule,
this::tunaRule
};
}
How about return List<Function<Boolean, Integer>> like this.
public class Example {
public List<Function<Boolean, Integer>> getFunctions(boolean t) {
return Arrays.asList(
this::magicNumber
);
}
public int magicNumber(boolean t) {
return (t) ? new Random().nextInt(11) : 0;
}
}

How to turn FibSupplier into a generic FiniteSupplier?

Considering I have the following class:
public class Problem2 extends Problem<Integer> {
#Override
public void run() {
result = toList(new FibSupplier(i -> (i <= 4_000_000)))
.stream()
.filter(i -> (i % 2 == 0))
.mapToInt(i -> i)
.sum();
}
#Override
public String getName() {
return "Problem 2";
}
private static <E> List<E> toList(final Iterator<E> iterator) {
List<E> list = new ArrayList<>();
while (iterator.hasNext()) {
list.add(iterator.next());
}
return list;
}
private class FibSupplier implements Iterator<Integer> {
private final IntPredicate hasNextPredicate;
private int beforePrevious = 0;
private int previous = 1;
public FibSupplier(final IntPredicate hasNextPredicate) {
this.hasNextPredicate = hasNextPredicate;
}
#Override
public boolean hasNext() {
return hasNextPredicate.test(previous);
}
#Override
public Integer next() {
int result = beforePrevious + previous;
beforePrevious = previous;
previous = result;
return result;
}
}
}
If you take a look at FibSupplier you can see that it exposes a generalized problem, even though it has a specialized implementation here, what I've managed to extract are:
It has a Predicate.
It has initial variables.
It has a variable that needs to be tested by the predicate.
It has a custom next() method.
My attempt to generalize this was with the following, note that I use a generic version for now instead of a specialized integer version:
public class FiniteSupplier<E> implements Iterator<E> {
private final Predicate<E> predicate;
public FiniteSupplier(final Predicate<E> predicate) {
this.predicate = predicate;
}
#Override
public boolean hasNext() {
throw new UnsupportedOperationException("Not supported yet.");
}
#Override
public E next() {
throw new UnsupportedOperationException("Not supported yet.");
}
}
I want to be able to call FiniteSupplier with a predicate, however now I do not really know how to implement the other requirements I have managed to extract. I understand it could be done by extending the FiniteSupplier and making it abstract, but is that the correct way to do it?
The method test(int/Integer) can be used as Predicate<Integer> and as IntPredicate. The compiler does the conversion:
IntPredicate ip = (i) -> i>0;
Predicate<Integer> pi = (i) -> i>0;
Predicate<Integer> ip2pi = ip::test;
IntPredicate pi2ip = pi::test;
But you can't cast the two types as they are not assignable. IntPredicate does not extend Predicate.
So just use ::test when you create FibSupplier:
new FibSupplier(p) => new FibSupplier(p::test)
Or do that in a constructor. I'd introduce a new abstract type FiniteIntSupplier with an extra constructor that takes an IntSupplier and converts it to a general Supplier:
public FiniteIntSupplier(IntPredicate p) {
this(p::test);
}

java generic addition

I'm attempting implement the add method mentioned in the Generic sparse matrix addition question
class Matrix<T extends Number>
{
private T add(T left, T right)
{
if (left instanceof Integer)
{
return new Integer(((Integer)left).intValue() + ((Integer)right).intValue());
}
}
The compiler errors with found java.lang.Integer Required T at the line where I return a new Integer. I'm not sure what I'm missing since T extends Number and Integer is a subclass of Number.
The compiler doesn't let you do this because T might be some other class, such as Double.
You know that T is Integer from the instanceof check, but the compiler doesn't.
Java's type system is simply not capable of expressing this. Here is a work around.
Create an interface Numeric that provides the numeric operations you are interested in, and write its implementations for the data types you are interested in.
interface Numeric<N> {
public N add(N n1, N n2);
public N subtract(N n1, N n2);
// etc.
}
class IntNumeric extends Numeric<Integer> {
public static final Numeric<Integer> INSTANCE = new IntNumeric();
private IntNumeric() {
}
public Integer add(Integer a, Integer b) {
return a + b;
}
public Integer subtract(Integer a, Integer b) {
return a - b;
}
// etc.
}
And rewrite your Matrix class constructor to accept this implementation.
class Matrix<N> {
private final Numeric<N> num;
private final List<List<N>> contents;
public Matrix(Numeric<N> num) {
this.num = num;
this.contents = /* Initialization code */;
}
public Matrix<N> add(Matrix<N> that) {
Matrix<N> out = new Matrix<N>(num);
for( ... ) {
for( ... ) {
out.contents.get(i).set(j,
num.add(
this.contents.get(i).get(j),
that.contents.get(i).get(j),
)
);
}
}
return out;
}
}
// Use site
Matrix<Integer> m = new Matrix<Integer>(IntNumeric.INSTANCE);
Hope that helps.
"I'm not sure what I'm missing since T extends Number and Integer is a subclass of Number."
This statement is false. In general if you have:
public class B extends A {
}
public class C extends A {
}
it does not mean that B can be cast to C. So writing something like:
public <T extends A> T method(T arg) {
return (B)arg;
}
and you calling it with B b = (B)method(C); is obviously wrong.
package generics;
public class Box<T> {
public T j,k;
int l;
float f;
#SuppressWarnings("unchecked")
public void add(T j,T k) {
this.j = j;
this.k=k;
if(j.toString().contains("."))
{
this.f=Float.parseFloat(j.toString())+Float.parseFloat(k.toString());
} else{
this.l=Integer.parseInt(j.toString())+Integer.parseInt(k.toString());
}
}
public int getInt() {
return l;
}
public float getFloat() {
return f;
}
public static void main(String[] args) {
Box<Integer> integerBox = new Box<Integer>();
Box<Float> floatBox = new Box<Float>();
integerBox.add(new Integer(10),new Integer(20));
floatBox.add(new Float(2.2),new Float(3.3));
System.out.printf("Integer Value :%d\n\n", integerBox.getInt());
System.out.printf("float Value :%f\n", floatBox.getFloat());
}
}

Real time sorted by value, auto-discarding, bounded collection ?

I spent some time to try to make a collection that:
1) is sorted by value (not by key)
2) is sorted each time an element is added or modified
3) is fixed size and discard automatically smallest/biggest element depending of the sort way
4) is safe thread
So 3) and 4) I think it is quite ok. For 1) and 2) it was a bit more tricky. I spent quite a long time on this thread, experimenting the different sample, but one big issue is that the collection are sorted only once when object are inserted.
Anyway, I try to implement my own collection, which is working (shouldn't be used for huge data as it is sorted quite often) but I'm not so happy with the design. Especially in the fact that my value objects are constrained to be Observable (which is good) but not comparable so I had to use a dirty instanceof + exception for this.
Any sugestion to improve this ?
Here is the code:
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Observable;
import java.util.Observer;
public class SortedDiscardingSyncArray<K, V extends Observable> implements Observer {
// Comparison way (ascendent or descendant)
public static enum ComparisonWay
{
DESC,
ASC;
}
// this is backed by a List (and ArrayList impl)
private List<ArrayElement> array;
// Capacity, configurable, over this limit, an item will be discarded
private int MAX_CAPACITY = 200;
// default is descending comparison
private ComparisonWay compareWay = ComparisonWay.DESC;
public SortedDiscardingSyncArray(ComparisonWay compareWay, int mAX_CAPACITY) {
super();
this.compareWay = compareWay;
MAX_CAPACITY = mAX_CAPACITY;
array = new ArrayList <ArrayElement>(MAX_CAPACITY);
}
public SortedDiscardingSyncArray(int mAX_CAPACITY) {
super();
MAX_CAPACITY = mAX_CAPACITY;
array = new ArrayList<ArrayElement>(MAX_CAPACITY);
}
public SortedDiscardingSyncArray() {
super();
array = new ArrayList <ArrayElement>(MAX_CAPACITY);
}
public boolean put(K key, V value)
{
try {
return put (new ArrayElement(key, value, this));
} catch (Exception e) {
e.printStackTrace();
return false;
}
finally
{
sortArray();
}
}
private synchronized boolean put(ArrayElement ae)
{
if (array.size() < MAX_CAPACITY)
{
return array.add(ae);
}
// check if last one is greater/smaller than current value to insert
else if (ae.compareTo(array.get(MAX_CAPACITY-1)) < 0)
{
array.remove(MAX_CAPACITY - 1);
return array.add(ae);
}
// else we don't insert
return false;
}
public V getValue (int index)
{
return array.get(index).getValue();
}
public V getValue (K key)
{
for (ArrayElement ae : array)
{
if (ae.getKey().equals(key)) return ae.getValue();
}
return null;
}
public K getKey (int index)
{
return array.get(index).getKey();
}
private void sortArray()
{
Collections.sort(array);
}
public synchronized void setValue(K key, V newValue) {
for (ArrayElement ae : array)
{
if (ae.getKey().equals(key))
{
ae.setValue(newValue);
return;
}
}
}
public int size() {
return array.size();
}
#Override
public void update(java.util.Observable arg0, Object arg1) {
sortArray();
}
public static void main(String[] args) {
// some test on the class
SortedDiscardingSyncArray<String, ObservableSample> myData = new SortedDiscardingSyncArray<String, ObservableSample>(ComparisonWay.DESC, 20);
String Ka = "Ka";
String Kb = "Kb";
String Kc = "Kc";
String Kd = "Kd";
myData.put(Ka, new ObservableSample(0));
myData.put(Kb, new ObservableSample(3));
myData.put(Kc, new ObservableSample(1));
myData.put(Kd, new ObservableSample(2));
for (int i=0; i < myData.size(); i++)
{
System.out.println(myData.getKey(i).toString() + " - " + myData.getValue(i).toString());
}
System.out.println("Modifying data...");
myData.getValue(Kb).setValue(12);
myData.getValue(Ka).setValue(34);
myData.getValue(Kd).setValue(9);
myData.getValue(Kc).setValue(19);
for (int i=0; i < myData.size(); i++)
{
System.out.println(myData.getKey(i).toString() + " - " + myData.getValue(i).toString());
}
}
private class ArrayElement implements Comparable <ArrayElement> {
public ArrayElement(K key, V value, Observer obs) throws Exception {
super();
// don't know how to handle that case
// maybe multiple inheritance would have helped here ?
if (! (value instanceof Comparable)) throw new Exception("Object must be 'Comparable'");
this.key = key;
this.value = value;
value.addObserver(obs);
}
public String toString()
{
StringBuffer sb = new StringBuffer();
sb.append(key);
sb.append(" - ");
sb.append(value);
return sb.toString();
}
private K key;
private V value;
public K getKey() {
return key;
}
public V getValue() {
return value;
}
public synchronized void setValue(V value) {
this.value = value;
}
#SuppressWarnings("unchecked")
#Override
public int compareTo(ArrayElement o) {
int c;
if (compareWay == ComparisonWay.DESC) c = ((Comparable<V>) o.getValue()).compareTo(this.getValue());
else c = ((Comparable<V>) this.getValue()).compareTo(o.getValue());
if (c != 0) {
return c;
}
Integer hashCode1 = o.getValue().hashCode();
Integer hashCode2 = this.getValue().hashCode();
// we don't check the compare way for hash code (useless ?)
return hashCode1.compareTo(hashCode2);
}
}
}
And the other class for testing purpose:
import java.util.Observable;
public class ObservableSample extends Observable implements Comparable <ObservableSample>
{
private Integer value = 0;
public ObservableSample(int value) {
this.value = value;
setChanged();
notifyObservers();
}
public String toString()
{
return String.valueOf(this.value);
}
public void setValue(Integer value) {
this.value = value;
setChanged();
notifyObservers();
}
public Integer getValue() {
return value;
}
#Override
public int compareTo(ObservableSample o) {
int c;
c = (this.getValue()).compareTo(o.getValue());
if (c != 0) {
return c;
}
Integer hashCode1 = o.getValue().hashCode();
Integer hashCode2 = this.getValue().hashCode();
// we don't check the compare way for hash code (useless ?)
return hashCode1.compareTo(hashCode2);
}
}
Collections are difficult to write, maybe you should look for an existing implementation.
Try checking out ImmutableSortedSet from Guava.
You can have a marker interface
public interface ComparableObservable extends Observable, Comparable {
}
and then change
SortedDiscardingSyncArray<K, V extends Observable>
to
SortedDiscardingSyncArray<K, V extends ComparableObservable>
to avoid the explicit cast.
Other than that the code is quite verbose and I didn't follow it completely. I would also suggest having a look at guava or (apache) commons-collections library to explore if you can find something reusable.
You can write generic wildcards with multiple bounds. So change your declaration of <K, V extends Observable> to <K, V extends Observable & Comparable<V>> and then you can treat V as if it implements both interfaces, without an otherwise empty and useless interface.
Another few things: Pick a naming convention, and stick with it. The one I use is that a name such as MAX_CAPACITY would be used for a static final field (i.e. a constant, such as a default) and that the equivalent instance field would be maxCapacity Names such as mAX_CAPACITY would be right out of the question.
See: Oracle's naming conventions for Java
Instead of using a ComparisonWay enum, I would take a custom Comparator. Much more flexible, and doesn't replicate something that already exists.
See: the Comparator API docs
Your code, as written, is not thread safe. In particular an observed element calling the unsynchronized update method may thus invoke sortArray without obtaining the proper lock. FindBugs is a great tool that catches a lot of problems like this.
Your ObservableSample does not really follow good practices with regards to how it implements Comparable, in that it does not really compare data values but instead the hashCode. The hashCode is essentially arbitrary and collisions are quite possible. Additionally, the Comparable interface requests that usually you should be "consistent with Equals", for which you also might want to take a look at the documentation for the Object class's equals method
Yes, it sounds like a lot of work, but if you go through it and do it right you will save yourself astounding amounts of debugging effort down the road. If you do not do these properly and to the spec, you will find that when you place it in Sets or Maps your keys or values strangely disappear, reappear, or get clobbered. And it will depend on which version of Java you run, potentially!
Here is a version updated. Still not completly sure it is safe thread but findbugs tool didn't give so usefull tips. Also for the comparisonWay, I don't want to constraint the user to develop its own comparator, I want to keep the things simple.
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Observable;
import java.util.Observer;
public class SortedDiscardingSyncArray<K, V extends Observable & Comparable<V>> implements Observer {
// Comparison way (ascendent or descendant)
public static enum ComparisonWay { DESC, ASC; }
// this is backed by a List (and ArrayList)
private List<ArrayElement> array;
// Capacity, configurable, over this limit, an item will be discarded
private int maxCapacity = 200;
// default is descending comparison
private ComparisonWay compareWay = ComparisonWay.DESC;
public SortedDiscardingSyncArray(ComparisonWay compareWay, int maxCapacity) {
super();
this.compareWay = compareWay;
this.maxCapacity = maxCapacity;
array = new ArrayList <ArrayElement>(maxCapacity);
}
public SortedDiscardingSyncArray(int maxCapacity) {
super();
this.maxCapacity = maxCapacity;
array = new ArrayList<ArrayElement>(maxCapacity);
}
public SortedDiscardingSyncArray() {
super();
array = new ArrayList <ArrayElement>(maxCapacity);
}
// not synchronized, but calling internal sync put command
public boolean put(K key, V value)
{
try {
return put (new ArrayElement(key, value, this));
} catch (Exception e) {
e.printStackTrace();
return false;
}
finally
{
sortArray();
}
}
private synchronized boolean put(ArrayElement ae)
{
if (array.size() < maxCapacity) return array.add(ae);
// check if last one is greater/smaller than current value to insert
else if (ae.compareTo(array.get(maxCapacity-1)) < 0)
{
array.remove(maxCapacity - 1);
return array.add(ae);
}
// else we don't insert and return false
return false;
}
public V getValue (int index)
{
return array.get(index).getValue();
}
public V getValue (K key)
{
for (ArrayElement ae : array)
{
if (ae.getKey().equals(key)) return ae.getValue();
}
return null;
}
public K getKey (int index)
{
return array.get(index).getKey();
}
private synchronized void sortArray()
{
Collections.sort(array);
}
public synchronized void setValue(K key, V newValue) {
for (ArrayElement ae : array)
{
if (ae.getKey().equals(key))
{
ae.setValue(newValue);
return;
}
}
}
public int size() {
return array.size();
}
#Override
public void update(java.util.Observable arg0, Object arg1) {
sortArray();
}
public static void main(String[] args) {
// some test on the class
SortedDiscardingSyncArray<String, ObservableSample> myData = new SortedDiscardingSyncArray<String, ObservableSample>(ComparisonWay.DESC, 20);
String Ka = "Ka";
String Kb = "Kb";
String Kc = "Kc";
String Kd = "Kd";
myData.put(Ka, new ObservableSample(0));
myData.put(Kb, new ObservableSample(3));
myData.put(Kc, new ObservableSample(1));
myData.put(Kd, new ObservableSample(2));
for (int i=0; i < myData.size(); i++)
{
System.out.println(myData.getKey(i).toString() + " - " + myData.getValue(i).toString());
}
System.out.println("Modifying data...");
myData.getValue(Kb).setValue(12);
myData.getValue(Ka).setValue(34);
myData.getValue(Kd).setValue(9);
myData.getValue(Kc).setValue(19);
for (int i=0; i < myData.size(); i++)
{
System.out.println(myData.getKey(i).toString() + " - " + myData.getValue(i).toString());
}
}
private class ArrayElement implements Comparable <ArrayElement> {
public ArrayElement(K key, V value, Observer obs) throws Exception {
super();
this.key = key;
this.value = value;
value.addObserver(obs);
}
public String toString()
{
StringBuffer sb = new StringBuffer();
sb.append(key);
sb.append(" - ");
sb.append(value);
return sb.toString();
}
private K key;
private V value;
public K getKey() {
return key;
}
public V getValue() {
return value;
}
public synchronized void setValue(V value) {
this.value = value;
}
#Override
public int compareTo(ArrayElement o) {
int c;
if (compareWay == ComparisonWay.DESC) c = o.getValue().compareTo(this.getValue());
else c = this.getValue().compareTo(o.getValue());
if (c != 0) {
return c;
}
Integer hashCode1 = o.getValue().hashCode();
Integer hashCode2 = this.getValue().hashCode();
// we don't check the compare way for hash code (useless ?)
return hashCode1.compareTo(hashCode2);
}
}
}

Cast Int to enum in Java

What is the correct way to cast an Int to an enum in Java given the following enum?
public enum MyEnum
{
EnumValue1,
EnumValue2
}
MyEnum enumValue = (MyEnum) x; //Doesn't work???
Try MyEnum.values()[x] where x must be 0 or 1, i.e. a valid ordinal for that enum.
Note that in Java enums actually are classes (and enum values thus are objects) and thus you can't cast an int or even Integer to an enum.
MyEnum.values()[x] is an expensive operation. If the performance is a concern, you may want to do something like this:
public enum MyEnum {
EnumValue1,
EnumValue2;
public static MyEnum fromInteger(int x) {
switch(x) {
case 0:
return EnumValue1;
case 1:
return EnumValue2;
}
return null;
}
}
If you want to give your integer values, you can use a structure like below
public enum A
{
B(0),
C(10),
None(11);
int id;
private A(int i){id = i;}
public int GetID(){return id;}
public boolean IsEmpty(){return this.equals(A.None);}
public boolean Compare(int i){return id == i;}
public static A GetValue(int _id)
{
A[] As = A.values();
for(int i = 0; i < As.length; i++)
{
if(As[i].Compare(_id))
return As[i];
}
return A.None;
}
}
You can try like this.
Create Class with element id.
public Enum MyEnum {
THIS(5),
THAT(16),
THE_OTHER(35);
private int id; // Could be other data type besides int
private MyEnum(int id) {
this.id = id;
}
public static MyEnum fromId(int id) {
for (MyEnum type : values()) {
if (type.getId() == id) {
return type;
}
}
return null;
}
}
Now Fetch this Enum using id as int.
MyEnum myEnum = MyEnum.fromId(5);
I cache the values and create a simple static access method:
public static enum EnumAttributeType {
ENUM_1,
ENUM_2;
private static EnumAttributeType[] values = null;
public static EnumAttributeType fromInt(int i) {
if(EnumAttributeType.values == null) {
EnumAttributeType.values = EnumAttributeType.values();
}
return EnumAttributeType.values[i];
}
}
Java enums don't have the same kind of enum-to-int mapping that they do in C++.
That said, all enums have a values method that returns an array of possible enum values, so
MyEnum enumValue = MyEnum.values()[x];
should work. It's a little nasty and it might be better to not try and convert from ints to Enums (or vice versa) if possible.
This not something that is usually done, so I would reconsider. But having said that, the fundamental operations are: int --> enum using EnumType.values()[intNum], and enum --> int using enumInst.ordinal().
However, since any implementation of values() has no choice but to give you a copy of the array (java arrays are never read-only), you would be better served using an EnumMap to cache the enum --> int mapping.
Use MyEnum enumValue = MyEnum.values()[x];
Here's the solution I plan to go with. Not only does this work with non-sequential integers, but it should work with any other data type you may want to use as the underlying id for your enum values.
public Enum MyEnum {
THIS(5),
THAT(16),
THE_OTHER(35);
private int id; // Could be other data type besides int
private MyEnum(int id) {
this.id = id;
}
public int getId() {
return this.id;
}
public static Map<Integer, MyEnum> buildMap() {
Map<Integer, MyEnum> map = new HashMap<Integer, MyEnum>();
MyEnum[] values = MyEnum.values();
for (MyEnum value : values) {
map.put(value.getId(), value);
}
return map;
}
}
I only need to convert id's to enums at specific times (when loading data from a file), so there's no reason for me to keep the Map in memory at all times. If you do need the map to be accessible at all times, you can always cache it as a static member of your Enum class.
In case it helps others, the option I prefer, which is not listed here, uses Guava's Maps functionality:
public enum MyEnum {
OPTION_1(-66),
OPTION_2(32);
private int value;
private MyEnum(final int value) {
this.value = value;
}
public int getValue() {
return this.value;
}
private static ImmutableMap<Integer, MyEnum> reverseLookup =
Maps.uniqueIndex(Arrays.asList(MyEnum.values())), MyEnum::getValue);
public static MyEnum fromInt(final int id) {
return reverseLookup.getOrDefault(id, OPTION_1);
}
}
With the default you can use null, you can throw IllegalArgumentException or your fromInt could return an Optional, whatever behavior you prefer.
Based on #ChadBefus 's answer and #shmosel comment, I'd recommend using this. (Efficient lookup, and works on pure java >= 8)
import java.util.stream.Collectors;
import java.util.function.Function;
import java.util.Map;
import java.util.Arrays;
public enum MyEnum {
OPTION_1(-66),
OPTION_2(32);
private int value;
private MyEnum(final int value) {
this.value = value;
}
public int getValue() {
return this.value;
}
private static Map<Integer, MyEnum> reverseLookup =
Arrays.stream(MyEnum.values()).collect(Collectors.toMap(MyEnum::getValue, Function.identity()));
public static MyEnum fromInt(final int id) {
return reverseLookup.getOrDefault(id, OPTION_1);
}
public static void main(String[] args) {
System.out.println(fromInt(-66).toString());
}
}
You can iterate over values() of enum and compare integer value of enum with given id like below:
public enum TestEnum {
None(0),
Value1(1),
Value2(2),
Value3(3),
Value4(4),
Value5(5);
private final int value;
private TestEnum(int value) {
this.value = value;
}
public int getValue() {
return value;
}
public static TestEnum getEnum(int value){
for (TestEnum e:TestEnum.values()) {
if(e.getValue() == value)
return e;
}
return TestEnum.None;//For values out of enum scope
}
}
And use just like this:
TestEnum x = TestEnum.getEnum(4);//Will return TestEnum.Value4
I hope this helps ;)
Wrote this implementation. It allows for missing values, negative values and keeps code consistent. The map is cached as well. Uses an interface and needs Java 8.
Enum
public enum Command implements OrdinalEnum{
PRINT_FOO(-7),
PRINT_BAR(6),
PRINT_BAZ(4);
private int val;
private Command(int val){
this.val = val;
}
public int getVal(){
return val;
}
private static Map<Integer, Command> map = OrdinalEnum.getValues(Command.class);
public static Command from(int i){
return map.get(i);
}
}
Interface
public interface OrdinalEnum{
public int getVal();
#SuppressWarnings("unchecked")
static <E extends Enum<E>> Map<Integer, E> getValues(Class<E> clzz){
Map<Integer, E> m = new HashMap<>();
for(Enum<E> e : EnumSet.allOf(clzz))
m.put(((OrdinalEnum)e).getVal(), (E)e);
return m;
}
}
In Kotlin:
enum class Status(val id: Int) {
NEW(0), VISIT(1), IN_WORK(2), FINISHED(3), CANCELLED(4), DUMMY(5);
companion object {
private val statuses = Status.values().associateBy(Status::id)
fun getStatus(id: Int): Status? = statuses[id]
}
}
Usage:
val status = Status.getStatus(1)!!
A good option is to avoid conversion from int to enum: for example, if you need the maximal value, you may compare x.ordinal() to y.ordinal() and return x or y correspondingly. (You may need to re-order you values to make such comparison meaningful.)
If that is not possible, I would store MyEnum.values() into a static array.
This is the same answer as the doctors but it shows how to eliminate the problem with mutable arrays. If you use this kind of approach because of branch prediction first if will have very little to zero effect and whole code only calls mutable array values() function only once. As both variables are static they will not consume n * memory for every usage of this enumeration too.
private static boolean arrayCreated = false;
private static RFMsgType[] ArrayOfValues;
public static RFMsgType GetMsgTypeFromValue(int MessageID) {
if (arrayCreated == false) {
ArrayOfValues = RFMsgType.values();
}
for (int i = 0; i < ArrayOfValues.length; i++) {
if (ArrayOfValues[i].MessageIDValue == MessageID) {
return ArrayOfValues[i];
}
}
return RFMsgType.UNKNOWN;
}
enum MyEnum {
A(0),
B(1);
private final int value;
private MyEnum(int val) {this.value = value;}
private static final MyEnum[] values = MyEnum.values();//cache for optimization
public static final getMyEnum(int value) {
try {
return values[value];//OOB might get triggered
} catch (ArrayOutOfBoundsException e) {
} finally {
return myDefaultEnumValue;
}
}
}

Categories

Resources