Que sont les énumérations et pourquoi sont-elles utiles?

488

Aujourd'hui, je parcourais quelques questions sur ce site et j'ai trouvé une mention d'une enum utilisation dans un modèle singleton sur les avantages supposés de la sécurité des threads pour une telle solution.

Je n'ai jamais utilisé enums et je programme en Java depuis plus de deux ans maintenant. Et apparemment, ils ont beaucoup changé. Maintenant, ils soutiennent même pleinement la POO en eux-mêmes.

Maintenant, pourquoi et pourquoi dois-je utiliser enum dans la programmation quotidienne?

Mat B.
la source
6
Dans son livre Effective Java, Second Edition , Joshua Bloch développe cette approche dans l' article 3: Appliquer la propriété Singleton avec un constructeur privé ou un type d'énumération , réimprimé dans Dr. Dobb's .
trashgod
doublon possible d' Enum en Java. Avantages?
finnw
Vous ne pouvez pas instancier des énumérations car il a un constructeur privé, elles sont instanciées au démarrage de jvm, donc son singleton, Enums, n'est pas sûr pour les threads.
Arnav Joshi

Réponses:

633

Vous devez toujours utiliser des énumérations lorsqu'une variable (en particulier un paramètre de méthode) ne peut en prendre qu'une parmi un petit ensemble de valeurs possibles. Les exemples seraient des choses comme les constantes de type (statut du contrat: "permanent", "temporaire", "apprenti"), ou les indicateurs ("exécuter maintenant", "différer l'exécution").

Si vous utilisez des énumérations au lieu d'entiers (ou de codes de chaîne), vous augmentez la vérification au moment de la compilation et évitez les erreurs de passer des constantes non valides, et vous documentez les valeurs autorisées à utiliser.

BTW, la surutilisation des énumérations peut signifier que vos méthodes en font trop (il est souvent préférable d'avoir plusieurs méthodes distinctes, plutôt qu'une méthode qui prend plusieurs indicateurs qui modifient ce qu'elle fait), mais si vous devez utiliser des indicateurs ou des codes de type, les énumérations sont le chemin à parcourir.

Par exemple, quel est le meilleur?

/** Counts number of foobangs.
 * @param type Type of foobangs to count. Can be 1=green foobangs,
 * 2=wrinkled foobangs, 3=sweet foobangs, 0=all types.
 * @return number of foobangs of type
 */
public int countFoobangs(int type)

contre

/** Types of foobangs. */
public enum FB_TYPE {
 GREEN, WRINKLED, SWEET, 
 /** special type for all types combined */
 ALL;
}

/** Counts number of foobangs.
 * @param type Type of foobangs to count
 * @return number of foobangs of type
 */
public int countFoobangs(FB_TYPE type)

Un appel de méthode comme:

int sweetFoobangCount = countFoobangs(3);

devient alors:

int sweetFoobangCount = countFoobangs(FB_TYPE.SWEET);

Dans le deuxième exemple, il est immédiatement clair quels types sont autorisés, les documents et l'implémentation ne peuvent pas être désynchronisés et le compilateur peut les appliquer. En outre, un appel non valide comme

int sweetFoobangCount = countFoobangs(99);

n'est plus possible.

sleske
la source
41
Si vous utilisez des énumérations et souhaitez autoriser une combinaison de valeurs, utilisez EnumSet. Cela vient avec toutes sortes d'aides soignées, comme la finale publique statique EnumSet <FB_TYPE> ALL = EnumSet.allOf (FB_TYPE.class);
RobAu
20
Ces réponses sont celles que j'aime vraiment voir chez SO parce que quelqu'un y a fait de gros efforts, bon travail je comprends les énumérations maintenant!
Dédié le
1
Je ne pense pas que ce soit vrai you should *always* use enums when a variable can only take one out of a small set of possible values. L'utilisation de valeurs constantes comme «indicateur binaire» (avec oring logique ) peut être utile pour les applications en temps réel où vous manquez de mémoire.
Elist
@Elist utilisant des énumérations augmente la lisibilité de vos codes.Si vous utilisez des constantes à un moment ou à un autre, vous ou votre successeur ne savez pas pourquoi il est utilisé ...
:)
136

Pourquoi utiliser une fonction de langage de programmation? La raison pour laquelle nous avons des langues est

  1. Les programmeurs peuvent exprimer efficacement et correctement les algorithmes sous une forme que les ordinateurs peuvent utiliser.
  2. Les mainteneurs doivent comprendre les algorithmes que d'autres ont écrits et apporter correctement les modifications.

Les énumérations améliorent à la fois la probabilité de correction et la lisibilité sans écrire beaucoup de passe-partout. Si vous êtes prêt à écrire un passe-partout, vous pouvez "simuler" des énumérations:

public class Color {
    private Color() {} // Prevent others from making colors.
    public static final Color RED = new Color();
    public static final Color AMBER = new Color();
    public static final Color GREEN = new Color();
}

Vous pouvez maintenant écrire:

Color trafficLightColor = Color.RED;

Le passe-partout ci-dessus a à peu près le même effet que

public enum Color { RED, AMBER, GREEN };

Les deux fournissent le même niveau de vérification de l'aide du compilateur. Boilerplate est juste plus typé. Mais économiser beaucoup de frappe rend le programmeur plus efficace (voir 1), c'est donc une fonctionnalité intéressante.

Cela vaut également la peine pour au moins une autre raison:

Instructions de changement

Une chose que la static finalsimulation ENUM ci-dessus ne vous donne est bien des switchcas. Pour les types enum, le commutateur Java utilise le type de sa variable pour déduire la portée des cas enum, donc pour ce qui enum Colorprécède, vous devez simplement dire:

Color color = ... ;
switch (color) {
    case RED:
        ...
        break;
}

Notez que ce n'est pas Color.REDdans les cas. Si vous n'utilisez pas enum, la seule façon d'utiliser des quantités nommées avec switchest quelque chose comme:

public Class Color {
    public static final int RED = 0;
    public static final int AMBER = 1;
    public static final int GREEN = 2;
}

Mais maintenant, une variable pour contenir une couleur doit avoir un type int. Le bon compilateur vérifiant l'énumération et la static finalsimulation a disparu. Pas heureux.

Un compromis consiste à utiliser un membre à valeur scalaire dans la simulation:

public class Color {
    public static final int RED_TAG = 1;
    public static final int AMBER_TAG = 2;
    public static final int GREEN_TAG = 3;

    public final int tag;

    private Color(int tag) { this.tag = tag; } 
    public static final Color RED = new Color(RED_TAG);
    public static final Color AMBER = new Color(AMBER_TAG);
    public static final Color GREEN = new Color(GREEN_TAG);
}

Maintenant:

Color color = ... ;
switch (color.tag) {
    case Color.RED_TAG:
        ...
        break;
}

Mais attention, encore plus de passe-partout!

Utilisation d'une énumération comme singleton

Sur le passe-partout ci-dessus, vous pouvez voir pourquoi une énumération fournit un moyen d'implémenter un singleton. Au lieu d'écrire:

public class SingletonClass {
    public static final void INSTANCE = new SingletonClass();
    private SingletonClass() {}

    // all the methods and instance data for the class here
}

puis y accéder avec

SingletonClass.INSTANCE

on peut juste dire

public enum SingletonClass {
    INSTANCE;

    // all the methods and instance data for the class here
}

ce qui nous donne la même chose. Nous pouvons nous en tirer car les énumérations Java sont implémentées en tant que classes complètes avec seulement un peu de sucre syntaxique saupoudré sur le dessus. C'est encore moins passe-partout, mais ce n'est pas évident à moins que l'idiome ne vous soit familier. Je n'aime pas non plus le fait que vous obteniez les diverses fonctions d'énumération même si elles n'ont pas beaucoup de sens pour le singleton: ordet values, etc. (Il y a en fait une simulation plus délicate où Color extends Integercela fonctionnera avec switch, mais c'est tellement difficile montre clairement pourquoi enumest une meilleure idée.)

Sécurité des fils

La sécurité des threads n'est un problème potentiel que lorsque les singletons sont créés paresseusement sans verrouillage.

public class SingletonClass {
    private static SingletonClass INSTANCE;
    private SingletonClass() {}
    public SingletonClass getInstance() {
        if (INSTANCE == null) INSTANCE = new SingletonClass();
        return INSTANCE;
    }

    // all the methods and instance data for the class here
}

Si de nombreux threads appellent getInstancesimultanément alors qu'il INSTANCEest toujours nul, un nombre quelconque d'instances peut être créé. C'est mauvais. La seule solution est d'ajouter un synchronizedaccès pour protéger la variable INSTANCE.

Cependant, le static finalcode ci-dessus n'a pas ce problème. Il crée l'instance avec impatience au moment du chargement de la classe. Le chargement des classes est synchronisé.

Le enumsingleton est effectivement paresseux car il n'est initialisé qu'à la première utilisation. L'initialisation Java est également synchronisée, donc plusieurs threads ne peuvent pas initialiser plus d'une instance de INSTANCE. Vous obtenez un singleton initialisé paresseusement avec très peu de code. Le seul point négatif est la syntaxe plutôt obscure. Vous devez connaître l'idiome ou bien comprendre comment fonctionnent le chargement et l'initialisation des classes pour savoir ce qui se passe.

Gène
la source
15
Ce dernier paragraphe a vraiment clarifié la situation de singleton pour moi. Merci! Tout lecteur qui écume devrait relire cela.
Basil Bourque
Je lisais ceci, stackoverflow.com/questions/16771373/… . Maintenant, je suis confus avec votre dernier paragraphe. Comment l'énumération ne fournit pas la fonction d'initialisation de laïque?
Deepankar Singh
static finalles champs sont initialisés au moment de l'initialisation de la classe , et non au moment du chargement. C'est exactement la même chose qu'avec enumune initialisation constante (en fait, ils sont identiques sous le capot). C'est pourquoi essayer d'implémenter du code d'initialisation paresseux «intelligent» pour des singletons a toujours été inutile, même dans la première version Java.
Holger
42

Outre les cas d'utilisation déjà mentionnés, je trouve souvent les énumérations utiles pour implémenter le modèle de stratégie, en suivant certaines directives de base de la POO:

  1. Avoir le code où se trouvent les données (c'est-à-dire dans l'énumération elle-même - ou souvent dans les constantes enum, qui peuvent remplacer les méthodes).
  2. Implémenter une interface (ou plus) afin de ne pas lier le code client à l'énumération (qui ne devrait fournir qu'un ensemble d'implémentations par défaut).

L'exemple le plus simple serait un ensemble d' Comparatorimplémentations:

enum StringComparator implements Comparator<String> {
    NATURAL {
        @Override
        public int compare(String s1, String s2) {
            return s1.compareTo(s2);
        }
    },
    REVERSE {
        @Override
        public int compare(String s1, String s2) {
            return NATURAL.compare(s2, s1);
        }
    },
    LENGTH {
        @Override
        public int compare(String s1, String s2) {
            return new Integer(s1.length()).compareTo(s2.length());
        }
    };
}

Ce «modèle» peut être utilisé dans des scénarios beaucoup plus complexes, faisant un usage intensif de tous les avantages qui accompagnent l'énumération: itération sur les instances, s'appuyant sur leur ordre implicite, récupération d'une instance par son nom, méthodes statiques fournissant la bonne instance pour des contextes spécifiques, etc. Et vous avez toujours tout cela caché derrière l'interface afin que votre code fonctionne avec des implémentations personnalisées sans modification au cas où vous voudriez quelque chose qui n'est pas disponible parmi les "options par défaut".

J'ai vu cela appliqué avec succès pour modéliser le concept de granularité temporelle (quotidienne, hebdomadaire, etc.) où toute la logique était encapsulée dans une énumération (choisir la bonne granularité pour une plage de temps donnée, un comportement spécifique lié à chaque granularité comme constant méthodes, etc.). Et pourtant, la Granularityvue de la couche service n'était qu'une interface.

Costi Ciudatu
la source
2
Vous pouvez également ajouter CASE_INSENSITIVE { @Override public int compare(String s1, String s2) { return s1.compareToIgnoreCase(s2); }. Un avantage non encore mentionné est que vous bénéficiez d'une prise en charge robuste de la sérialisation; le formulaire persistant contient uniquement le nom de classe et le nom constant, sans dépendre des détails d'implémentation de vos comparateurs.
Holger
32

Aucune des autres réponses couvertes qui rendent les énumérations particulièrement puissantes est la possibilité d'avoir des méthodes de modèle . Les méthodes peuvent faire partie de l'énumération de base et être remplacées par chaque type. Et, avec le comportement attaché à l'énumération, il élimine souvent le besoin de constructions if-else ou d'instructions switch comme le montre ce billet de blog - d'où enum.method()vient ce qui à l'origine serait exécuté à l'intérieur du conditionnel. Le même exemple montre également l'utilisation d'importations statiques avec des énumérations et la production de code DSL beaucoup plus propre.

Certaines autres qualités intéressantes incluent le fait que les énumérations fournissent une implémentation pour equals(), toString()et hashCode()et implémentent Serializableet Comparable.

Pour un aperçu complet de tout ce que les énumérations ont à offrir, je recommande fortement Thinking in Java 4th edition de Bruce Eckel qui consacre un chapitre entier au sujet. Les exemples impliquant un jeu Rock, Paper, Scissors (ie RoShamBo) comme enums sont particulièrement éclairants.

orangepips
la source
23

À partir de documents Java -

Vous devez utiliser les types d'énumération chaque fois que vous avez besoin de représenter un ensemble fixe de constantes. Cela inclut les types d'énumérations naturels tels que les planètes de notre système solaire et les ensembles de données où vous connaissez toutes les valeurs possibles au moment de la compilation, par exemple, les choix dans un menu, les drapeaux de ligne de commande, etc.

Un exemple courant consiste à remplacer une classe par un ensemble de constantes int finales statiques privées (dans un nombre raisonnable de constantes) par un type enum. Fondamentalement, si vous pensez connaître toutes les valeurs possibles de "quelque chose" au moment de la compilation, vous pouvez représenter cela comme un type enum. Les énumérations offrent une lisibilité et une flexibilité sur une classe avec des constantes.

Peu d'autres avantages que je peux penser aux types d'énumération. Ils sont toujours une instance d'une classe d'énumération particulière (d'où le concept d'utilisation des énumérations comme singleton). Un autre avantage est que vous pouvez utiliser des énumérations comme type dans une instruction switch-case. Vous pouvez également utiliser toString () sur l'énumération pour les imprimer sous forme de chaînes lisibles.

Fèves fraîches
la source
8
Souhaitez-vous utiliser une énumération pour les 366 jours de l'année? C'est un ensemble fixe (366) de constantes (les jours ne changent pas). Cela suggère donc que vous devriez. : - / Je limiterais la taille de l'ensemble fixe.
moinudin
2
@marcog Avec un peu de réflexion intelligente, il pourrait être possible de résumer les jours d'une semaine et les jours de chaque mois dans une énumération compacte.
James P.
1
En parlant de jours de la semaine… DayOfWeekenum est désormais prédéfini, intégré à Java 8 et versions ultérieures dans le cadre de java.time (et rétroporté vers Java 6 & 7 et Android ).
Basil Bourque
19

Maintenant, pourquoi et pourquoi devrais-je utiliser enum dans la programmation quotidienne?

Vous pouvez utiliser une énumération pour représenter un petit ensemble fixe de constantes ou un mode de classe interne tout en augmentant la lisibilité. De plus, Enums peut appliquer une certaine rigidité lorsqu'il est utilisé dans les paramètres de méthode. Ils offrent la possibilité intéressante de transmettre des informations à un constructeur comme dans l' exemple des planètes sur le site d'Oracle et, comme vous l'avez découvert, permettent également de créer un motif singleton de manière simple.

ex: Locale.setDefault(Locale.US)lit mieux que Locale.setDefault(1)et applique l'utilisation de l'ensemble fixe de valeurs affiché dans un IDE lorsque vous ajoutez le .séparateur au lieu de tous les entiers.

James P.
la source
@arnt J'ai aussi corrigé la grammaire de la question. Merci.
James P.
13

Enums énumérer un ensemble fixe de valeurs, de manière auto-documentée.
Ils rendent votre code plus explicite et moins sujet aux erreurs.

Pourquoi ne pas utiliser String, ou int, au lieu de Enum, pour les constantes?

  1. Le compilateur n'autorisera pas les fautes de frappe , ni les valeurs hors de l'ensemble fixe, car les énumérations sont des types en soi. Conséquences:
    • Vous n'aurez pas à écrire une condition préalable (ou un manuel if) pour vous assurer que votre argument est dans la plage valide.
    • L' invariant de type est gratuit.
  2. Les énumérations peuvent avoir un comportement, comme toute autre classe.
  3. Vous auriez probablement besoin d'une quantité de mémoire similaire pour utiliser Strings, de toute façon (cela dépend de la complexité de la Enum).

De plus, chacune des Enuminstances de est une classe, pour laquelle vous pouvez définir son comportement individuel.

De plus, ils assurent la sécurité des threads lors de la création des instances (lorsque l'énumération est chargée), ce qui a été très utile pour simplifier le modèle Singleton .

Ce blog illustre certaines de ses applications, comme une machine d'état pour un analyseur.

afsantos
la source
13

Il est utile de savoir que ce enumssont comme les autres classes avec des Constantchamps et un private constructor.

Par exemple,

public enum Weekday
{
  MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
} 

Le compilateur le compile comme suit;

class Weekday extends Enum
{
  public static final Weekday MONDAY  = new Weekday( "MONDAY",   0 );
  public static final Weekday TUESDAY = new Weekday( "TUESDAY ", 1 );
  public static final Weekday WEDNESDAY= new Weekday( "WEDNESDAY", 2 );
  public static final Weekday THURSDAY= new Weekday( "THURSDAY", 3 );
  public static final Weekday FRIDAY= new Weekday( "FRIDAY", 4 );
  public static final Weekday SATURDAY= new Weekday( "SATURDAY", 5 );
  public static final Weekday SUNDAY= new Weekday( "SUNDAY", 6 );

  private Weekday( String s, int i )
  {
    super( s, i );
  }

  // other methods...
}
À l'infini
la source
12

enumsignifie énumération, c'est-à-dire mention (un certain nombre de choses) une par une.

Une énumération est un type de données qui contient un ensemble fixe de constantes.

OU

An enumest comme un class, avec un ensemble fixe d'instances connues au moment de la compilation.

Par exemple:

public class EnumExample {
    interface SeasonInt {
        String seasonDuration();
    }

    private enum Season implements SeasonInt {
        // except the enum constants remaining code looks same as class
        // enum constants are implicitly public static final we have used all caps to specify them like Constants in Java
        WINTER(88, "DEC - FEB"), SPRING(92, "MAR - JUN"), SUMMER(91, "JUN - AUG"), FALL(90, "SEP - NOV");

        private int days;
        private String months;

        Season(int days, String months) { // note: constructor is by default private 
            this.days = days;
            this.months = months;
        }

        @Override
        public String seasonDuration() {
            return this+" -> "+this.days + "days,   " + this.months+" months";
        }

    }
    public static void main(String[] args) {
        System.out.println(Season.SPRING.seasonDuration());
        for (Season season : Season.values()){
            System.out.println(season.seasonDuration());
        }

    }
}

Avantages de l'énumération:

  • enum améliore la sécurité des types lors de la vérification au moment de la compilation pour éviter les erreurs lors de l'exécution.
  • l'énumération peut être facilement utilisée dans le commutateur
  • l'énumération peut être parcourue
  • enum peut avoir des champs, des constructeurs et des méthodes
  • enum peut implémenter de nombreuses interfaces mais ne peut étendre aucune classe car elle étend en interne la classe Enum

pour plus

Premraj
la source
9

Qu'est-ce qu'une énumération

  • enum est un mot clé défini pour l'énumération d'un nouveau type de données. Les énumérations Typesafe doivent être utilisées généreusement. En particulier, ils constituent une alternative robuste aux simples constantes String ou int utilisées dans des API beaucoup plus anciennes pour représenter des ensembles d'éléments associés.

Pourquoi utiliser enum

  • les énumérations sont des sous-classes implicitement finales de java.lang.Enum
  • si une énumération est membre d'une classe, elle est implicitement statique
  • new ne peut jamais être utilisé avec une énumération, même au sein du type énumération lui-même
  • name et valueOf utilisent simplement le texte des constantes enum, tandis que toString peut être remplacé pour fournir n'importe quel contenu, si désiré
  • pour les constantes énum, ​​égal et == équivalent à la même chose, et peuvent être utilisés de manière interchangeable
  • les constantes énum sont implicitement finales statiques publiques

Remarque

  • les énumérations ne peuvent étendre aucune classe.
  • Une énumération ne peut pas être une superclasse.
  • l'ordre d'apparition des constantes enum est appelé leur «ordre naturel» et définit également l'ordre utilisé par les autres éléments: compareTo, ordre d'itération des valeurs, EnumSet, EnumSet.range.
  • Une énumération peut avoir des constructeurs, des blocs statiques et d'instance, des variables et des méthodes mais ne peut pas avoir de méthodes abstraites.
tinker_fairy
la source
4
Vous n'expliquez pas pourquoi utiliser les énumérations. Vous venez de lister plusieurs propriétés des énumérations sous des en-têtes non liés.
Duncan Jones
@DuncanJones les termes final, static ne donnent-ils pas le but d'utiliser des énumérations?
tinker_fairy
8

En dehors de tout ce que disent les autres. Dans un ancien projet pour lequel je travaillais, beaucoup de communications entre les entités (applications indépendantes) utilisaient des entiers qui représentaient un petit ensemble. Il était utile de déclarer l'ensemble comme enumavec des méthodes statiques pour obtenir un enumobjet valueet vice versa. Le code avait l'air plus propre, la convivialité du boîtier de commutation et une écriture plus facile dans les journaux.

enum ProtocolType {
    TCP_IP (1, "Transmission Control Protocol"), 
    IP (2, "Internet Protocol"), 
    UDP (3, "User Datagram Protocol");

    public int code;
    public String name;

    private ProtocolType(int code, String name) {
        this.code = code;
        this.name = name;
    }

    public static ProtocolType fromInt(int code) {
    switch(code) {
    case 1:
        return TCP_IP;
    case 2:
        return IP;
    case 3:
        return UDP;
    }

    // we had some exception handling for this
    // as the contract for these was between 2 independent applications
    // liable to change between versions (mostly adding new stuff)
    // but keeping it simple here.
    return null;
    }
}

Créer un enumobjet à partir des valeurs reçues (par exemple 1,2) à l'aide de l' ProtocolType.fromInt(2) écriture dans les journaux à l'aidemyEnumObj.name

J'espère que cela t'aides.

sErVerdevIL
la source
6

Enum hérite de toutes les méthodes de Objectclasse et de classe abstraite Enum. Vous pouvez donc utiliser ses méthodes de réflexion, de multithreading, de sérilisation, comparables, etc. Si vous déclarez simplement une constante statique au lieu d'Enum, vous ne pouvez pas. En plus de cela, la valeur d'Enum peut également être transmise à la couche DAO.

Voici un exemple de programme à démontrer.

public enum State {

    Start("1"),
    Wait("1"),
    Notify("2"),
    NotifyAll("3"),
    Run("4"),
    SystemInatilize("5"),
    VendorInatilize("6"),
    test,
    FrameworkInatilize("7");

    public static State getState(String value) {
        return State.Wait;
    }

    private String value;
    State test;

    private State(String value) {
        this.value = value;
    }

    private State() {
    }

    public String getValue() {
        return value;
    }

    public void setCurrentState(State currentState) {
        test = currentState;
    }

    public boolean isNotify() {
        return this.equals(Notify);
    }
}

public class EnumTest {

    State test;

    public void setCurrentState(State currentState) {
        test = currentState;
    }

    public State getCurrentState() {
        return test;
    }

    public static void main(String[] args) {
        System.out.println(State.test);
        System.out.println(State.FrameworkInatilize);
        EnumTest test=new EnumTest();
        test.setCurrentState(State.Notify);
        test. stateSwitch();
    }

    public void stateSwitch() {
        switch (getCurrentState()) {
        case Notify:
            System.out.println("Notify");
            System.out.println(test.isNotify());
            break;
        default:
            break;
        }
    }
}
abishkar bhattarai
la source
4

ENum signifie "Enumerated Type". Il s'agit d'un type de données ayant un ensemble fixe de constantes que vous définissez vous-même.

Steve
la source
Vous n'avez pas expliqué pourquoi utiliser une énumération.
Duncan Jones
4
Oui je l'ai fait. Vous l'utilisez pour stocker un ensemble fixe de constantes que vous définissez vous-même. L'application spécifique en est à vous. Il n'y a rien de tel que de dire quand, pourquoi ou comment utiliser quelque chose. Cela dépend des besoins du développeur. Tout ce que vous devez comprendre, c'est ce que c'est et comment cela fonctionne.
Steve
4

À mon avis, toutes les réponses que vous avez obtenues jusqu'à présent sont valables, mais d'après mon expérience, je l'exprimerais en quelques mots:

Utilisez des énumérations si vous souhaitez que le compilateur vérifie la validité de la valeur d'un identifiant.

Sinon, vous pouvez utiliser des chaînes comme vous l'avez toujours fait (vous avez probablement défini des "conventions" pour votre application) et vous serez très flexible ... mais vous n'obtiendrez pas une sécurité à 100% contre les fautes de frappe sur vos chaînes et vous ne les réaliserez que en exécution.

Rafa
la source
3

Utilisez des énumérations pour la SÉCURITÉ DES TYPES, il s'agit d'une fonction de langue, vous obtiendrez donc généralement:

  • Prise en charge du compilateur (voir immédiatement les problèmes de type)
  • Prise en charge des outils dans les IDE (auto-complétion dans le cas du commutateur, cas manquants, forcer par défaut, ...)
  • Dans certains cas, les performances d'énumération sont également excellentes ( EnumSet , alternative de type sécurisée aux "indicateurs de bits" traditionnels basés sur l'int . )

Les énumérations peuvent avoir des méthodes, des constructeurs, vous pouvez même utiliser des énumérations à l'intérieur des énumérations et combiner des énumérations avec des interfaces.

Considérez les énumérations comme des types pour remplacer un ensemble bien défini de constantes int (que Java a «hérité» de C / C ++) et, dans certains cas, pour remplacer les indicateurs de bits.

Le livre Effective Java 2nd Edition a un chapitre entier à leur sujet et donne plus de détails. Voir également ce post Stack Overflow .

Christophe Roussy
la source
2

Java vous permet de restreindre une variable à l'une des rares valeurs prédéfinies, en d'autres termes, une valeur d'une liste énumérée. L'utilisation enumspeut aider à réduire les bogues dans votre code. Voici un exemple de l' enumsextérieur d'une classe:

enums coffeesize{BIG , HUGE , OVERWHELMING }; 
//This semicolon is optional.

Cela limite coffeesizeà avoir soit: BIG, HUGEou OVERWHELMINGcomme variable.

Rahul Prajapat
la source
2

Enum? Pourquoi devrait-il être utilisé? Je pense que c'est mieux compris quand vous l'utiliserez. J'ai la même expérience.

Supposons que vous ayez créé, supprimé, édité et lu une opération de base de données.

Maintenant, si vous créez une énumération en tant qu'opération:

public enum operation {
    create("1")
    delete("2")
    edit("3")
    read("4")

    // You may have is methods here
    public boolean isCreate() {
        return this.equals(create);
    }
    // More methods like the above can be written

}

Maintenant, vous pouvez déclarer quelque chose comme:

private operation currentOperation;

// And assign the value for it 
currentOperation = operation.create

Vous pouvez donc l'utiliser de plusieurs façons. Il est toujours bon d'avoir une énumération pour des choses spécifiques car le fonctionnement de la base de données dans l'exemple ci-dessus peut être contrôlé en vérifiant l' opération en cours . On peut peut-être dire que cela peut aussi être accompli avec des variables et des valeurs entières. Mais je crois qu'Enum est un moyen plus sûr et pour un programmeur.

Autre chose: je pense que chaque programmeur aime le booléen , n'est-ce pas? Parce qu'il ne peut stocker que deux valeurs, deux valeurs spécifiques. Enum peut donc être considéré comme ayant le même type d'installations où un utilisateur définira combien et quel type de valeur il stockera, juste d'une manière légèrement différente. :)

Abhishek Bhandari
la source
1

Jusqu'à présent, je n'ai jamais eu besoin d'utiliser des énumérations. J'ai lu à leur sujet depuis qu'ils ont été introduits dans la version 1.5 ou tigre, comme on l'appelait à l'époque. Ils n'ont jamais vraiment résolu un «problème» pour moi. Pour ceux qui l'utilisent (et j'en vois beaucoup), je suis sûr que cela sert certainement à quelque chose. Juste ma 2 chique.

happybuddha
la source
1

Il y a beaucoup de réponses ici, je veux juste en mentionner deux spécifiques:

1) Utilisation comme constantes dans l' Switch-caseinstruction. Switch case ne vous permettra pas d'utiliser des objets String pour la casse. Les énumérations sont utiles. Plus: http://www.javabeat.net/2009/02/how-to-use-enum-in-switch/

2) Implémentation Singleton Design Pattern- Enum encore, vient à la rescousse. Utilisation, ici: Quelle est la meilleure approche pour utiliser un Enum comme singleton en Java?

Vishal Verma
la source
1

Ce qui m'a donné le moment Ah-Ha, c'est cette prise de conscience: qu'Enum a un constructeur privé accessible uniquement via l'énumération publique:

enum RGB {
    RED("Red"), GREEN("Green"), BLUE("Blue");

    public static final String PREFIX = "color ";

    public String getRGBString() {
        return PREFIX + color;
    }

    String color;

    RGB(String color) {
        this.color = color;
    }
}

public class HelloWorld {
    public static void main(String[] args) {
        String c = RGB.RED.getRGBString();
        System.out.print("Hello " + c);
    }
}
djangofan
la source
1

Quant à moi pour rendre le code lisible à l'avenir, le cas d'énumération le plus utile est représenté dans l'extrait suivant:

public enum Items {
    MESSAGES, CHATS, CITY_ONLINE, FRIENDS, PROFILE, SETTINGS, PEOPLE_SEARCH, CREATE_CHAT
}

@Override
public boolean onCreateOptionsMenu(Menu menuPrm) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menuPrm);
    View itemChooserLcl;
    for (int i = 0; i < menuPrm.size(); i++) {
        MenuItem itemLcl  = menuPrm.getItem(i);
            itemChooserLcl = itemLcl.getActionView();
            if (itemChooserLcl != null) {
                 //here Im marking each View' tag by enume values:
                itemChooserLcl.setTag(Items.values()[i]);
                itemChooserLcl.setOnClickListener(drawerMenuListener);
            }
        }
    return true;
}
private View.OnClickListener drawerMenuListener=new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        Items tagLcl= (Items) v.getTag();
        switch (tagLcl){
            case MESSAGES: ;
            break;
            case CHATS : ;
            break;
            case CITY_ONLINE : ;
            break;
            case FRIENDS : ;
            break;
            case  PROFILE: ;
            break;
            case  SETTINGS: ;
            break;
            case  PEOPLE_SEARCH: ;
            break;
            case  CREATE_CHAT: ;
            break;
        }
    }
};
CodeToLife
la source
1

D'après mon expérience, j'ai vu que l'utilisation d'Enum rend parfois les systèmes très difficiles à modifier. Si vous utilisez un Enum pour un ensemble de valeurs spécifiques au domaine qui changent fréquemment et qu'il a beaucoup d'autres classes et composants qui en dépendent, vous pouvez envisager de ne pas utiliser un Enum.

Par exemple, un système commercial qui utilise un Enum pour les marchés / échanges. Il existe de nombreux marchés et il est presque certain qu'il y aura de nombreux sous-systèmes qui auront besoin d'accéder à cette liste de marchés. Chaque fois que vous voulez qu'un nouveau marché soit ajouté à votre système, ou si vous voulez supprimer un marché, il est possible que tout sous le soleil doive être reconstruit et libéré.

Un meilleur exemple serait quelque chose comme un type de catégorie de produit. Supposons que votre logiciel gère l'inventaire pour un grand magasin. Il existe de nombreuses catégories de produits et de nombreuses raisons pour lesquelles cette liste de catégories pourrait changer. Les gestionnaires peuvent vouloir stocker une nouvelle gamme de produits, se débarrasser d'autres gammes de produits et éventuellement réorganiser les catégories de temps en temps. Si vous devez reconstruire et redéployer tous vos systèmes simplement parce que les utilisateurs veulent ajouter une catégorie de produits, alors vous avez pris quelque chose qui devrait être simple et rapide (ajouter une catégorie) et le rendre très difficile et lent.

En résumé, les énumérations sont bonnes si les données que vous représentez sont très statiques dans le temps et ont un nombre limité de dépendances. Mais si les données changent beaucoup et ont beaucoup de dépendances, alors vous avez besoin de quelque chose de dynamique qui n'est pas vérifié au moment de la compilation (comme une table de base de données).

BradB
la source
1

Le singleton basé sur l'énumération

un regard moderne sur un vieux problème

Cette approche implémente le singleton en tirant parti de la garantie de Java que toute valeur d'énumération n'est instanciée qu'une seule fois dans un programme Java et que l'énumération prend en charge implicitement la sécurité des threads. Étant donné que les valeurs d'énumération Java sont accessibles globalement, elles peuvent donc être utilisées comme singleton.

public enum Singleton {
    SINGLETON; 
    public void method() { }
}

Comment cela marche-t-il? Eh bien, la ligne deux du code peut être considérée comme ceci:

public final static Singleton SINGLETON = new Singleton(); 

Et nous obtenons un bon vieux singleton initialisé.

N'oubliez pas que puisqu'il s'agit d'une énumération, vous pouvez toujours accéder à l'instance via Singleton.INSTANCE:

Singleton s = Singleton.INSTANCE;
Les avantages
  • Pour empêcher la création d'autres instances de singleton pendant la désérialisation, utilisez un singleton basé sur l'énumération car la sérialisation de l'énumération est prise en charge par JVM. La sérialisation et la désérialisation Enum fonctionnent différemment des objets Java normaux. La seule chose qui est sérialisée est le nom de la valeur enum. Pendant le processus de désérialisation, la valueOfméthode enum est utilisée avec le nom désérialisé pour obtenir l'instance souhaitée.
  • Le singleton basé sur Enum permet de se protéger des attaques par réflexion. Le type enum étend en fait la Enumclasse java . La raison pour laquelle la réflexion ne peut pas être utilisée pour instancier des objets de type enum est parce que la spécification java interdit et que la règle est codée dans l'implémentation de la newInstanceméthode de la Constructorclasse, qui est généralement utilisée pour créer des objets via la réflexion:
if ((clazz.getModifiers() & Modifier.ENUM) != 0)
    throw new IllegalArgumentException("Cannot reflectively create enum objects");
  • Enum n'est pas censé être cloné car il doit y avoir exactement une instance de chaque valeur.
  • Le code le plus laconique de toutes les réalisations singleton.
Désavantages
  • Le singleton basé sur l'énumération ne permet pas l'initialisation paresseuse.
  • Si vous avez changé votre conception et que vous vouliez convertir votre singleton en multiton, enum ne le permettrait pas. Le modèle multiton est utilisé pour la création contrôlée de plusieurs instances, qu'il gère via l'utilisation d'un map. Plutôt que d'avoir une seule instance par application (par exemple le java.lang.Runtime), le modèle multiton assure à la place une seule instance par clé .
  • L'énumération n'apparaît que dans Java 5, vous ne pouvez donc pas l'utiliser dans la version précédente.

Il existe plusieurs réalisations de modèle singleton chacune avec des avantages et des inconvénients.

  • Désireux de charger singleton
  • Double verrouillage à double vérification
  • Idiome du titulaire d'initialisation à la demande
  • Le singleton basé sur l'énumération

La description détaillée de chacun d'eux est trop verbeuse donc je viens de mettre un lien vers un bon article - Tout ce que vous voulez savoir sur Singleton

Oleg Poltoratskii
la source
0

J'utiliserais les énumérations comme un instrument de cartographie utile, en évitant plusieurs à if-else condition que certaines méthodes soient implémentées.

public enum Mapping {

    ONE("1"),
    TWO("2");

    private String label;

    private Mapping(String label){
        this.label = label;
    }

    public static Mapping by(String label) {

        for(Mapping m: values() {
            if(m.label.equals(label)) return m;
        }

        return null;
    }

}

Ainsi, la méthode by(String label)vous permet d'obtenir la valeur énumérée par non énumérée. De plus, on peut inventer une cartographie entre 2 énumérations. Peut également essayer «1 à plusieurs» ou «plusieurs à plusieurs» en plus de la relation par défaut «un à un»

Au final, enumc'est une classe Java. Vous pouvez donc avoir une mainméthode à l'intérieur, ce qui peut être utile lorsque vous devez effectuer argsimmédiatement des opérations de mappage .

TEH EMPRAH
la source
0

Au lieu de faire un tas de déclarations const int

Vous pouvez les regrouper tous en 1 enum

Donc tout est organisé par le groupe commun auquel ils appartiennent

Vincent Tang
la source
0

Les énumérations sont comme des classes. Comme la classe, il a également des méthodes et des attributs.

Les différences avec la classe sont les suivantes: 1. les constantes d'énumération sont publiques, statiques, finales. 2. une énumération ne peut pas être utilisée pour créer un objet et elle ne peut pas étendre d'autres classes. Mais il peut implémenter des interfaces.

Shetu
la source
0

En plus de @BradB Answer:

C'est tellement vrai ... C'est étrange que ce soit la seule réponse qui mentionne cela. Lorsque les débutants découvrent des énumérations, ils prennent rapidement cela comme un tour de magie pour une vérification d'identifiant valide pour le compilateur. Et lorsque le code est destiné à être utilisé sur des systèmes distribués, ils pleurent ... un mois plus tard. Maintenir la compatibilité descendante avec les énumérations qui contiennent une liste de valeurs non statique est une véritable préoccupation et une douleur. En effet, lorsque vous ajoutez une valeur à une énumération existante, son type change (malgré le nom ne change pas).

"Ho, attends, ça peut ressembler au même type, non? Après tout, ce sont des énumérations avec le même nom - et ne sont-elles pas de simples entiers sous le capot?" Et pour ces raisons, votre compilateur ne signalera probablement pas l'utilisation d'une définition du type lui-même là où il attendait l'autre. Mais en fait, ce sont (de la manière la plus importante) des types différents. Plus important encore, ils ont différents domaines de données - des valeurs acceptables compte tenu du type. En ajoutant une valeur, nous avons effectivement changé le type de l'énumération et cassons donc la compatibilité descendante.

En conclusion: utilisez-le quand vous le souhaitez, mais vérifiez bien que le domaine de données utilisé est un ensemble fixe fini, déjà connu .

Nicolas Voron
la source