vendredi 29 juin 2012

Java enum et sa valeur entière

Il m'arrive d'utiliser les enum en java pour décrire une propriété (attribut) surtout dans le cas ou la valeur est une liste exhaustive.
Par exemple une énumération qui représente les unités de mesure :
public enum UniteEnum {
  PIXEL, CENTIMETRE, MILLIMETRE, POUCE
}

Cette énumération peut être utilisé comme attribut dans la classe suivante :
public class Longeur {
    private UniteEnum unite;
    private int valeur;
}
Pour persister la classe Longeur dans une base de donnée relationnelle on la fait correspondre à une table
create table longeur (
  valeur number(10),
  unite number(1)
);
Le type de la colonne unité est un nombre et non pas un String, il est plus simple de gérer une énumération en faisons correspondre sa valeur à un nombre qu'à une chaîne de caractère. Malheureusement dans le langage Java ce cas n'est pas géré, il faut alors ajouter quelques modifications dans UniteEnum pour simplifier la conversion depuis l'enum vers le nombre et inversement.
On ajoute un attribut qui représente la valeur entière de chaque enum et on définie un constructeur qui prend cette valeur comme paramètre
public enum UniteEnum {
    
    PIXEL(0),
    CENTIMETRE(1),
    MILLIMETRE(2),
    POUCE(3);

    private int intValue;

    UniteEnum(int intValue) {
        this.intValue = intValue;
    }
}
Il nous faut maintenant deux méthodes, une pour avoir la valeur entière d'un enum et une autre qui retourne un enum depuis sa valeur entière.

    public int value(){
        return this.intValue;
    }

    public static UniteEnum fromValue(int value){
       UniteEnum[] enums = UniteEnum.values();
        for (UniteEnum anEnum : enums) {
            if (anEnum.value() == value)
                return anEnum;
        }
        return null;
   }

On peut optimiser ce code surtout dans la méthode fromValue à la ligne 6

 UniteEnum[] enums = UniteEnum.values();

si cette ligne est appeler plusieurs fois on risque d'avoir des problèmes de performance, il serait mieux de la faire sortir dans une variable statique, pour avoir finalement ce code :
public enum UniteEnum {

    PIXEL(0),
    CENTIMETRE(1),
    MILLIMETRE(2),
    POUCE(3);

    private final static UniteEnum[] enums = UniteEnum.values();
    private int intValue;

    UniteEnum(int intValue) {
        this.intValue = intValue;
    }

    public int value(){
        return this.intValue;
    }

    public static UniteEnum fromValue(int value){
        for (UniteEnum anEnum : enums) {
            if (anEnum.value() == value)
                return anEnum;
        }
        return null;
    }
}
On exécute le test suivant en utilisant junit pour vérifier la conversion
public class UniteEnumTest {

    @Test
    public void testGetFromInt() {
        assertEquals(UniteEnum.PIXEL, UniteEnum.fromValue(0));
        assertEquals(UniteEnum.CENTIMETRE, UniteEnum.fromValue(1));
        assertEquals(UniteEnum.POUCE, UniteEnum.fromValue(3));

        assertNull("Aucune unité avec cette valeur", UniteEnum.fromValue(50));

        assertEquals(0, UniteEnum.PIXEL.value());
        assertEquals(1, UniteEnum.CENTIMETRE.value());
        assertEquals(3, UniteEnum.POUCE.value());
    }
}