Quelle est la bonne façon de convertir un Int en une énumération en Java étant donné l'énumération suivante?
public enum MyEnum
{
EnumValue1,
EnumValue2
}
MyEnum enumValue = (MyEnum) x; //Doesn't work???
Quelle est la bonne façon de convertir un Int en une énumération en Java étant donné l'énumération suivante?
public enum MyEnum
{
EnumValue1,
EnumValue2
}
MyEnum enumValue = (MyEnum) x; //Doesn't work???
Réponses:
Essayez MyEnum.values()[x]
où x
doit être 0
ou 1
, c'est-à-dire un ordinal valide pour cette énumération.
Notez qu'en Java, les énumérations sont en fait des classes (et les valeurs d'énumération sont donc des objets) et donc vous ne pouvez pas convertir un int
ou même Integer
en une énumération.
MyEnum.values()
en cache car c'est cher. c'est-à-dire si vous l'appelez des centaines de fois.
MyEnum.values()[x]
est une opération coûteuse. Si les performances sont un problème, vous voudrez peut-être faire quelque chose comme ceci:
public enum MyEnum {
EnumValue1,
EnumValue2;
public static MyEnum fromInteger(int x) {
switch(x) {
case 0:
return EnumValue1;
case 1:
return EnumValue2;
}
return null;
}
}
MyEnum.values()[x]
comme une opération coûteuse. Je ne sais pas comment cela fonctionne dans les détails, mais pour moi, il semble que l'accès à un élément dans un tableau ne serait pas très grave, alias temps constant. Si le tableau doit être construit, cela prend du temps O (n), qui est le même temps d'exécution que votre solution.
values()
génère un nouveau tableau à chaque fois, car les tableaux sont mutables, il ne serait donc pas sûr de retourner le même plusieurs fois. Les instructions switch ne sont pas nécessairement O (n), elles peuvent être compilées pour sauter des tables. Les affirmations de Lorenzo semblent donc justifiées.
myEnum = myEnumValues[i]
le même i
élément sera renvoyé dans l'énumération sans modifications.
Si vous voulez donner vos valeurs entières, vous pouvez utiliser une structure comme ci-dessous
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;
}
}
Vous pouvez essayer comme ça.
Créer une classe avec l'ID d'élément.
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;
}
}
Maintenant, récupérez cette énumération en utilisant id comme int.
MyEnum myEnum = MyEnum.fromId(5);
Je mets en cache les valeurs et crée une méthode d'accès statique simple:
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];
}
}
values
le même nom que la méthode values()
. J'utilise cachedValues
pour le nom du champ.
Les énumérations Java n'ont pas le même type de mappage enum-à-int qu'en C ++.
Cela dit, toutes values
les énumérations ont une méthode qui renvoie un tableau de valeurs d'énumération possibles, donc
MyEnum enumValue = MyEnum.values()[x];
devrait marcher. C'est un peu méchant et il pourrait être préférable de ne pas essayer de convertir de int
s en Enum
s (ou vice versa) si possible.
Ce n'est pas quelque chose qui se fait habituellement, donc je reconsidérerais. Mais cela étant dit, les opérations fondamentales sont: int -> enum en utilisant EnumType.values () [intNum], et enum -> int en utilisant EnumInst.ordinal ().
Cependant, étant donné que toute implémentation de values () n'a pas d'autre choix que de vous donner une copie du tableau (les tableaux java ne sont jamais en lecture seule), vous seriez mieux servi en utilisant un EnumMap pour mettre en cache le mappage enum -> int.
Voici la solution avec laquelle je prévois aller. Non seulement cela fonctionne avec des entiers non séquentiels, mais cela devrait fonctionner avec tout autre type de données que vous voudrez peut-être utiliser comme id sous-jacent pour vos valeurs d'énumération.
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;
}
}
Je n'ai besoin de convertir les identifiants en énumérations qu'à des moments spécifiques (lors du chargement de données à partir d'un fichier), il n'y a donc aucune raison pour moi de conserver la carte en mémoire à tout moment. Si vous avez besoin que la carte soit accessible à tout moment, vous pouvez toujours la mettre en cache en tant que membre statique de votre classe Enum.
clearCachedValues
lorsque vous avez fini de l'utiliser (qui redéfinit le champ privé sur null). Je considère MyEnum.fromInt(i)
plus facile à comprendre que de contourner un objet cartographique.
Au cas où cela aiderait les autres, l'option que je préfère, qui n'est pas répertoriée ici, utilise la fonctionnalité Maps de Guava :
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);
}
}
Avec la valeur par défaut que vous pouvez utiliser null
, vous pouvez throw IllegalArgumentException
ou fromInt
pouvez retourner un Optional
, quel que soit le comportement que vous préférez.
Map<Integer, MyEnum> reverseLookup = Arrays.stream(MyEnum.values()).collect(Collectors.toMap(MyEnum::getValue, Function.identity()));
getValue()
méthode.
Vous pouvez parcourir l' values()
énumération et comparer la valeur entière de l'énumération avec celle donnée id
ci-dessous:
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
}
}
Et utilisez comme ceci:
TestEnum x = TestEnum.getEnum(4);//Will return TestEnum.Value4
j'espère que cela vous aidera;)
Sur la base de la réponse de @ChadBefus et du commentaire de @shmosel, je recommanderais d'utiliser ceci. (Recherche efficace et fonctionne sur java pur> = 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());
}
}
Une bonne option consiste à éviter la conversion de int
à enum
: par exemple, si vous avez besoin de la valeur maximale, vous pouvez comparer x.ordinal () à y.ordinal () et renvoyer x ou y en conséquence. (Vous devrez peut-être réorganiser vos valeurs pour que cette comparaison soit significative.)
Si ce n'est pas possible, je stockerais MyEnum.values()
dans un tableau statique.
C'est la même réponse que les médecins, mais elle montre comment éliminer le problème avec les tableaux mutables. Si vous utilisez d'abord ce type d'approche en raison de la prédiction de branche, il aura très peu ou pas d'effet et le code entier n'appellera la fonction de valeurs de tableau mutable () qu'une seule fois. Comme les deux variables sont statiques, elles ne consommeront pas de mémoire n * pour chaque utilisation de cette énumération également.
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;
}
}
}
À 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 écrit cette implémentation. Il permet les valeurs manquantes, les valeurs négatives et maintient la cohérence du code. La carte est également mise en cache. Utilise une interface et a besoin de 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;
}
}