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é enum
s 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.
Réponses:
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?
contre
Un appel de méthode comme:
devient alors:
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
n'est plus possible.
la source
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» (avecor
ing logique ) peut être utile pour les applications en temps réel où vous manquez de mémoire.Pourquoi utiliser une fonction de langage de programmation? La raison pour laquelle nous avons des langues est
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:
Vous pouvez maintenant écrire:
Le passe-partout ci-dessus a à peu près le même effet que
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 final
simulation ENUM ci-dessus ne vous donne est bien desswitch
cas. 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 quienum Color
précède, vous devez simplement dire:Notez que ce n'est pas
Color.RED
dans les cas. Si vous n'utilisez pas enum, la seule façon d'utiliser des quantités nommées avecswitch
est quelque chose comme:Mais maintenant, une variable pour contenir une couleur doit avoir un type
int
. Le bon compilateur vérifiant l'énumération et lastatic final
simulation a disparu. Pas heureux.Un compromis consiste à utiliser un membre à valeur scalaire dans la simulation:
Maintenant:
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:
puis y accéder avec
on peut juste dire
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:
ord
etvalues
, etc. (Il y a en fait une simulation plus délicate oùColor extends Integer
cela fonctionnera avec switch, mais c'est tellement difficile montre clairement pourquoienum
est 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.
Si de nombreux threads appellent
getInstance
simultanément alors qu'ilINSTANCE
est toujours nul, un nombre quelconque d'instances peut être créé. C'est mauvais. La seule solution est d'ajouter unsynchronized
accès pour protéger la variableINSTANCE
.Cependant, le
static final
code 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
enum
singleton 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 deINSTANCE
. 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.la source
static final
les 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'avecenum
une 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.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:
L'exemple le plus simple serait un ensemble d'
Comparator
implémentations: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
Granularity
vue de la couche service n'était qu'une interface.la source
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.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()
ethashCode()
et implémententSerializable
etComparable
.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.
la source
À partir de documents Java -
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.
la source
DayOfWeek
enum 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 ).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 queLocale.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.la source
Enum
s é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
, ouint
, au lieu deEnum
, pour les constantes?if
) pour vous assurer que votre argument est dans la plage valide.String
s, de toute façon (cela dépend de la complexité de laEnum
).De plus, chacune des
Enum
instances 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.
la source
Il est utile de savoir que ce
enums
sont comme les autres classes avec desConstant
champs et unprivate constructor
.Par exemple,
Le compilateur le compile comme suit;
la source
enum
signifie énumération, c'est-à-dire mention (un certain nombre de choses) une par une.OU
Par exemple:
Avantages de l'énumération:
pour plus
la source
Qu'est-ce qu'une énumération
Pourquoi utiliser enum
Remarque
la source
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
enum
avec des méthodes statiques pour obtenir unenum
objetvalue
et vice versa. Le code avait l'air plus propre, la convivialité du boîtier de commutation et une écriture plus facile dans les journaux.Créer un
enum
objet à 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.
la source
Enum hérite de toutes les méthodes de
Object
classe et de classe abstraiteEnum
. 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.
la source
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.
la source
À 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.
la source
Utilisez des énumérations pour la SÉCURITÉ DES TYPES, il s'agit d'une fonction de langue, vous obtiendrez donc généralement:
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 .
la source
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
enums
peut aider à réduire les bogues dans votre code. Voici un exemple de l'enums
extérieur d'une classe:Cela limite
coffeesize
à avoir soit:BIG
,HUGE
ouOVERWHELMING
comme variable.la source
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:
Maintenant, vous pouvez déclarer quelque chose comme:
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. :)
la source
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.
la source
Il y a beaucoup de réponses ici, je veux juste en mentionner deux spécifiques:
1) Utilisation comme constantes dans l'
Switch-case
instruction. 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?la source
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:
la source
Quant à moi pour rendre le code lisible à l'avenir, le cas d'énumération le plus utile est représenté dans l'extrait suivant:
la source
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).
la source
Le singleton basé sur l'énumération
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.
Comment cela marche-t-il? Eh bien, la ligne deux du code peut être considérée comme ceci:
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
Les avantagesSingleton.INSTANCE
:valueOf
méthode enum est utilisée avec le nom désérialisé pour obtenir l'instance souhaitée.Enum
classe 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 lanewInstance
méthode de laConstructor
classe, qui est généralement utilisée pour créer des objets via la réflexion:map
. Plutôt que d'avoir une seule instance par application (par exemple lejava.lang.Runtime
), le modèle multiton assure à la place une seule instance par clé .Il existe plusieurs réalisations de modèle singleton chacune avec des avantages et des inconvénients.
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
la source
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.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,
enum
c'est une classe Java. Vous pouvez donc avoir unemain
méthode à l'intérieur, ce qui peut être utile lorsque vous devez effectuerargs
immédiatement des opérations de mappage .la source
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
la source
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.
la source
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 .
la source