web-dev-qa-db-fra.com

Quel est l'avantage d'une énumération Java par rapport à une classe avec des champs finaux statiques publics?

Je connais très bien C # mais je commence à travailler davantage en Java. Je m'attendais à apprendre que les enums de Java étaient fondamentalement équivalents à ceux de C #, mais apparemment, ce n'est pas le cas. Au départ, j’étais enthousiaste à l’idée d’apprendre que Java enum pourrait contenir plusieurs éléments de données, ce qui semble très avantageux ( http://docs.Oracle.com/javase/tutorial/Java/javaOO /enum.html ). Cependant, depuis lors, j'ai trouvé beaucoup de fonctionnalités manquantes qui sont triviales en C #, telles que la possibilité d'attribuer facilement une certaine valeur à un élément enum et, par conséquent, la possibilité de convertir un entier en une énumération sans effort considérable ( ie Convertit la valeur entière en correspondance Java Enum ).

La question que je me pose est donc la suivante: existe-t-il un avantage à Java enum par rapport à une classe avec un groupe de champs finaux statiques publics? Ou fournit-il simplement une syntaxe plus compacte?

EDIT: Permettez-moi d'être plus clair. Quel est l’avantage de Java enum sur une classe avec un groupe de champs finaux statiques publics du même type ? Par exemple, dans l'exemple des planètes du premier lien, quel est l'avantage d'une énumération sur une classe avec ces constantes publiques:

public static final Planet MERCURY = new Planet(3.303e+23, 2.4397e6);
public static final Planet VENUS = new Planet(4.869e+24, 6.0518e6);
public static final Planet EARTH = new Planet(5.976e+24, 6.37814e6);
public static final Planet MARS = new Planet(6.421e+23, 3.3972e6);
public static final Planet JUPITER = new Planet(1.9e+27, 7.1492e7);
public static final Planet SATURN = new Planet(5.688e+26, 6.0268e7);
public static final Planet URANUS = new Planet(8.686e+25, 2.5559e7);
public static final Planet Neptune = new Planet(1.024e+26, 2.4746e7);

Autant que je sache, la réponse de casablanca est la seule à le satisfaire.

130
Craig W

Techniquement, on pourrait en effet considérer les enums comme une classe avec un groupe de constantes typées, et c’est en fait comment les constantes enum sont implémentées en interne. L'utilisation d'un enum vous donne cependant des méthodes utiles ( Enum javadoc ) que vous auriez sinon à implémenter vous-même, telles que Enum.valueOf.

75
casablanca
  1. Type sécurité et valeur sécurité.
  2. Singleton garanti.
  3. Possibilité de définir et de remplacer des méthodes.
  4. Possibilité d'utiliser des valeurs dans switch instruction case sans qualification.
  5. Séquentialisation intégrée des valeurs via ordinal().
  6. Sérialisation par nom et non par valeur, ce qui offre un degré de pérennité.
  7. EnumSet et EnumMap classes.
93
user207421

Personne n'a mentionné la possibilité de les utiliser dans des déclarations switch; Je vais ajouter ça aussi.

Cela permet d'utiliser des enums arbitrairement complexes de manière propre sans utiliser instanceof, des séquences potentiellement déroutantes if ou des valeurs de commutation non-string/int. L'exemple canonique est une machine à états.

73
Dave Newton

Le principal avantage est le type de sécurité. Avec un ensemble de constantes, toute valeur du même type intrinsèque peut être utilisée, introduisant des erreurs. Avec un enum, seules les valeurs applicables peuvent être utilisées.

Par exemple

public static final int SIZE_SMALL  = 1;
public static final int SIZE_MEDIUM = 2;
public static final int SIZE_LARGE  = 3;

public void setSize(int newSize) { ... }

obj.setSize(15); // Compiles but likely to fail later

contre

public enum Size { SMALL, MEDIUM, LARGE };

public void setSize(Size s) { ... }

obj.setSize( ? ); // Can't even express the above example with an enum
42
Jim Garrison

Il y a moins de confusion. Prenez Font par exemple. Il a un constructeur qui prend le nom du Font souhaité, sa taille et son style (new Font(String, int, int)). À ce jour, je ne me souviens pas si le style ou la taille vont en premier. Si Font avait utilisé un enum pour tous ses différents styles (PLAIN, BOLD, ITALIC, BOLD_ITALIC), son constructeur ressemblerait à Font(String, Style, int), évitant ainsi toute confusion. Malheureusement, enum n'était pas présent lors de la création de la classe Font et, étant donné que Java doit maintenir la compatibilité inverse, nous serons toujours confrontés à cette ambiguïté.

Bien entendu, il ne s'agit que d'un argument en faveur de l'utilisation d'une constante enum à la place de public static final. Les enums sont également parfaits pour des singletons et pour mettre en œuvre le comportement par défaut tout en permettant une personnalisation ultérieure (le modèle de stratégie ). Un exemple de ce dernier est le Java.nio.file ' OpenOption et StandardOpenOption : si un développeur souhaite créer son propre OpenOption non standard, il le peut.

42
Jeffrey

Il y a beaucoup de bonnes réponses ici, mais personne ne dit qu'il existe des implémentations hautement optimisées des classes/interfaces de l'API Collection spécifiquement pour les enums :

Ces classes spécifiques à une énumération acceptent uniquement les instances Enum (les EnumMap acceptent uniquement Enums comme clés) et, chaque fois que cela est possible, elles reviennent à une représentation compacte et à une manipulation de bits dans leur implémentation.

Qu'est-ce que cela signifie?

Si notre type Enum ne comporte pas plus de 64 éléments (la plupart des exemples réels Enum seront éligibles pour cela), les implémentations stockent les éléments dans une seule valeur long, chaque Enum instance en question sera associée à un bit de cette longueur de 64 bits long. Ajouter un élément à un EnumSet consiste simplement à définir le bit correct sur 1, le supprimer correspond simplement à 0. Tester si un élément se trouve dans le Set correspond à un seul test de masque binaire! Maintenant tu dois aimer Enums pour ça!

25
icza

exemple:

public class CurrencyDenom {
   public static final int PENNY = 1;
 public static final int NICKLE = 5;
 public static final int DIME = 10;
public static final int QUARTER = 25;}

Limitation de Java constantes

1) Pas de sécurité de type : Tout d’abord, il n’est pas de type-safe; vous pouvez affecter n'importe quelle valeur int valide à int, par exemple. 99 bien qu'il n'y ait pas de pièce de monnaie pour représenter cette valeur.

2) Aucune impression significative : la valeur d'impression de l'une de ces constantes affichera sa valeur numérique au lieu d'un nom significatif, p. Ex. lorsque vous imprimez NICKLE, il imprimera "5" au lieu de "NICKLE"

3) Aucun espace de nom : pour accéder à la constante currencyDenom, nous devons préfixer le nom de la classe, par exemple. CurrencyDenom.PENNY au lieu d’utiliser PENNY bien que cela puisse aussi être réalisé en utilisant l’importation statique dans JDK 1.5

Avantage de enum

1) Les énumérations dans Java sont de type sûr et ont leur propre espace de nom. Cela signifie que votre enum aura un type, par exemple "Devise" dans l'exemple ci-dessous et que vous ne pourrez attribuer aucune valeur autre que celle spécifiée dans les Constantes Enum.

public enum Currency {PENNY, NICKLE, DIME, QUARTER};

Currency coin = Currency.PENNY; coin = 1; //compilation error

2) Enum dans Java sont des types de référence comme classe ou interface et vous pouvez définir un constructeur, des méthodes et des variables à l'intérieur de Java Enum, ce qui le rend plus puissant qu'Enum en C et C++, comme indiqué dans exemple suivant du type Java Enum.

3) Vous pouvez spécifier des valeurs de constantes enum au moment de la création, comme indiqué dans l'exemple ci-dessous: énumération public {PENNY (1), NICKLE (5), DIME (10), QUARTER (25)}; Mais pour que cela fonctionne, vous devez définir une variable membre et un constructeur, car PENNY (1) appelle en réalité un constructeur qui accepte la valeur int, voir l'exemple ci-dessous.

public enum Currency {
    PENNY(1), NICKLE(5), DIME(10), QUARTER(25);
    private int value;

    private Currency(int value) {
            this.value = value;
    }
}; 

Référence: https://javarevisited.blogspot.com/2011/08/enum-in-Java-example-tutorial.html

11
Maverick

Comme vous l'avez déjà remarqué, le premier avantage des énumérations est la simplicité de la syntaxe. Mais le principal objectif des enums est de fournir un ensemble bien connu de constantes qui, par défaut, forment une plage et permettent d'effectuer une analyse de code plus complète via des contrôles de sécurité de type et de valeur.

Ces attributs d'énums aident à la fois un programmeur et un compilateur. Par exemple, supposons que vous voyiez une fonction qui accepte un entier. Qu'est-ce que cet entier pourrait signifier? Quel genre de valeurs pouvez-vous transmettre? Vous ne savez pas vraiment tout de suite. Mais si vous voyez une fonction qui accepte enum, vous connaissez très bien toutes les valeurs possibles que vous pouvez transmettre.

Pour le compilateur, les énumérations aident à déterminer une plage de valeurs et, sauf si vous affectez des valeurs spéciales à leurs membres, elles sont comprises entre 0 et plus. Cela permet de localiser automatiquement les erreurs dans le code via des contrôles de sécurité de type, etc. Par exemple, le compilateur peut vous avertir que vous ne gérez pas toutes les valeurs enum possibles dans votre instruction switch (c'est-à-dire lorsque vous n'avez pas la casse default et que vous ne gérez qu'une seule des N valeurs enum). Il vous avertit également lorsque vous convertissez un entier arbitraire en enum car la plage de valeurs de enum est inférieure à celle de l'entier et que cela peut déclencher des erreurs dans la fonction qui n'acceptent pas vraiment un entier. De plus, générer une table de sauts pour le commutateur devient plus facile lorsque les valeurs sont comprises entre 0 et plus.

Ceci est vrai non seulement pour Java, mais également pour les autres langages soumis à une vérification de type stricte. C, C++, D, C # sont de bons exemples.

11
user405725

Une énumération est implicitement finale, avec un constructeur privé, toutes ses valeurs sont du même type ou d'un sous-type, vous pouvez obtenir toutes ses valeurs en utilisant values(), obtient sa name() ou ordinal() valeur ou vous pouvez rechercher une énumération par numéro ou par nom.

Vous pouvez également définir des sous-classes (même si théoriquement final, quelque chose que vous ne pouvez pas faire autrement)

enum Runner implements Runnable {
    HI {
       public void run() {
           System.out.println("Hello");
       }
    }, BYE {
       public void run() {
           System.out.println("Sayonara");
       }
       public String toString() {
           return "good-bye";
       }
    }
 }

 class MYRunner extends Runner // won't compile.
4
Peter Lawrey

enum Avantages:

  1. Les énumérations sont sécuritaires au type, les champs statiques ne sont pas
  2. Il existe un nombre fini de valeurs (il n'est pas possible de passer une valeur enum non existante. Si vous avez des champs de classe statiques, vous pouvez commettre cette erreur)
  3. Chaque énumération peut avoir plusieurs propriétés (champs/getters) attribuées - encapsulation. Également quelques méthodes simples: YEAR.toSeconds () ou similaire. Comparez: Colors.RED.getHex () avec Colors.toHex (Colors.RED)

"comme la possibilité d'attribuer facilement une certaine valeur à un élément enum"

enum EnumX{
  VAL_1(1),
  VAL_200(200);
  public final int certainValue;
  private X(int certainValue){this.certainValue = certainValue;}
}

"et par conséquent la capacité de convertir un entier en un enum sans effort décent" Ajouter une méthode de conversion int en enum qui le fait. Ajoutez simplement HashMap statique contenant le mappage.

Si vous voulez vraiment convertir ord = VAL_200.ordinal () en val_200, utilisez simplement: EnumX.values ​​() [ord]

4
mabn

Une autre différence importante est que Java compilateur traite les champs static final de types primitifs et . ) Chaîne en tant que littéraux. Cela signifie que ces constantes deviennent inline. Il ressemble au préprocesseur C/C++#define. Voir this SO question . Ce n'est pas le cas avec les enums.

Vous obtenez la vérification du temps de compilation des valeurs valides lorsque vous utilisez une énumération. Regardez cette question.

Le plus gros avantage est enum Singletons sont faciles à écrire et thread-safe:

public enum EasySingleton{
    INSTANCE;
}

et

/**
* Singleton pattern example with Double checked Locking
*/
public class DoubleCheckedLockingSingleton{
     private volatile DoubleCheckedLockingSingleton INSTANCE;

     private DoubleCheckedLockingSingleton(){}

     public DoubleCheckedLockingSingleton getInstance(){
         if(INSTANCE == null){
            synchronized(DoubleCheckedLockingSingleton.class){
                //double checking Singleton instance
                if(INSTANCE == null){
                    INSTANCE = new DoubleCheckedLockingSingleton();
                }
            }
         }
         return INSTANCE;
     }
}

les deux sont similaires et il a traité la sérialisation par eux-mêmes en mettant en œuvre

//readResolve to prevent another instance of Singleton
    private Object readResolve(){
        return INSTANCE;
    }

plus

2
Premraj

Je pense qu'une enum ne peut pas être final, car le compilateur situé sous le capot génère des sous-classes pour chaque entrée enum.

Plus d'informations De source

0
Sitansu

Les énumérations qui sont affichées ici comportent de nombreux avantages, et je les crée en ce moment, comme le demande la question. Mais j'ai un enum avec 5-6 champs.

enum Planet{
EARTH(1000000, 312312321,31232131, "some text", "", 12),
....
other planets
....

Dans ce type de cas, lorsque vous avez plusieurs champs dans les énumérations, il est beaucoup plus difficile de comprendre quelle valeur appartient à quel champ car vous devez voir le constructeur et le regard.

Les classes avec les constantes static final et l'utilisation du modèle Builder pour créer de tels objets le rendent plus lisible. Mais, vous en perdriez tous les autres avantages, si vous en avez besoin. Un inconvénient de ces classes est que vous devez ajouter les objets Planet manuellement au list/set de Planets..

Je préfère toujours énum au dessus de cette classe, comme values() est pratique et on ne sait jamais si vous en avez besoin pour l'utiliser dans switch ou EnumSet ou EnumMap à l'avenir :)

0
Bikas Katwal