Quel est l'avantage de l'activation de Strings dans Java 7?


19

Lorsque je commençais à programmer en Java, le fait que les instructions switch ne prennent pas de chaînes me frustrait. Ensuite, en utilisant Enums, j'ai réalisé les avantages que vous obtenez avec eux plutôt que de transmettre des valeurs brutes - la sécurité du type (qui facilite la refactorisation) et la clarté pour les autres développeurs.

J'ai du mal à penser à une situation où avec SE7 je vais maintenant décider d'utiliser un commutateur avec des chaînes comme entrées plutôt que Enums. S'ils sont implémentés via la commutation de chaînes entières (par exemple plutôt que des correspondances partielles ou regex), il ne semble pas offrir moins de raisons pour que le code change.

Et avec les outils IDE et le rapport lecture / écriture du codage, je serais beaucoup plus heureux de générer automatiquement une énumération supplémentaire que de passer des valeurs de chaîne.

Quel avantage nous apportent-ils en tant que programmeurs? Moins de plaque de chaudière?

Il ne semble pas que la langue criait pour cette fonctionnalité. Bien qu'il y ait peut-être un cas d'utilisation que j'écarte.


Les chaînes sont déjà beaucoup utilisées dans les instructions switch, mais parce que les gens ne pouvaient pas les utiliser directement, ils ont eu recours à des solutions de contournement comme des arbres géants sinon ou à des conversions en énumérations. Les deux solutions de contournement rendent le code moins lisible. Les deux façons sont des solutions de contournement et pourquoi utiliser une solution de contournement si une solution implémentée en mode natif montre mieux les intentions des programmeurs.
Pieter B

@PieterB Cependant, une Enum ajoute une valeur sémantique plutôt que d'être une solution de contournement, ce qui apporte une sécurité de type (par exemple, une faute de frappe sera capturée au moment de la compilation plutôt que de conduire à un bogue). Cela nous permet également de refactoriser toutes les instances de la chaîne, telles qu'utilisées dans ce contexte , sans affecter les autres utilisations de cette chaîne (ce qui peut se produire assez souvent avec les objets de domaine).
anotherdave

Réponses:


12

Pour autant que je sache, la question est de savoir pourquoi l'encapsulation des constantes String dans enum n'a pas été considérée comme suffisante pour couvrir les besoins des utilisateurs de langue. Cela a été résolu dans la proposition de fonctionnalité officielle annoncée sur la liste de diffusion JDK 7 (projet Coin).

D'après ma lecture de la proposition, l'alternative à l'utilisation d'énumérations a été rejetée au motif qu'elle introduit des types de ballonnement. Pour votre commodité, la partie pertinente de la proposition est citée ci-dessous, la déclaration concernant les énumérations étant indiquée en gras :

AVANTAGE MAJEUR: Qu'est-ce qui fait de la proposition un changement favorable?

Des modèles de codage plus réguliers peuvent être utilisés pour des opérations sélectionnées sur la base d'un ensemble de valeurs de chaîne constantes; la signification de la nouvelle construction devrait être évidente pour les développeurs Java.

AVANTAGE MAJEUR: Pourquoi la plateforme est-elle meilleure si la proposition est adoptée?

Performances potentiellement meilleures pour le code de répartition basé sur des chaînes.

INCONVÉNIENT MAJEUR: Il y a toujours un coût.

Une implémentation et une complexité de test accrues pour le compilateur.

ALTERNATIVES: Les avantages et les avantages peuvent-ils être obtenus d'une manière ou d'une autre sans changement de langue?

Non; les tests chaînés if-then-else pour l'égalité des chaînes sont potentiellement coûteux et l' introduction d'une énumération pour ses constantes commutables, une par valeur de chaîne d'intérêt, ajouterait un autre type à un programme sans raison valable ...


la partie audacieuse est assez surprenante
Simon Bergot

1
@Simon, pour moi personnellement, cela se lit comme un traitement indirect, "nous perdrons la concurrence avec C # si nous continuons à nous en tenir aux méthodes pré-Java5 pour traiter de telles considérations". :) Pour un exemple de "méthodes pré-Java5", reportez-vous à JDK-1223179: activer les chaînes - soumis en 1995 et rapidement fermé comme ne sera pas résolu : "Ne retenez pas votre souffle. Rien de semblable à cela n'est dans nos plans . "
moucher

Merci, très intéressant de voir les raisons avancées dans la proposition. Il est toujours faux de dire que nous introduisons un type dans un programme "sans bonne cause" - nous sommes des programmeurs OO! :)
anotherdave

5
@anotherdave "orienté objet" justifie l'introduction de types uniquement lorsque ceux-ci ont un objectif significatif. Apparemment, l'opinion dominante chez JCP s'est avérée que l'utilisation d'énumérations comme encapsuleurs sans cervelle pour les constantes de chaîne dans le commutateur n'est pas considérée comme significative
GNAT

1
Wow, je suis surpris (dans le bon sens) de voir la proposition officielle contrer activement le type ballonnement. C'est rafraîchissant. Le type ballonnement est un énorme problème en Java.
Ben Lee

7

En plus de rendre le code plus lisible, il existe des gains de performances potentiels par rapport aux if/else ifcomparaisons. La pertinence du changement dépend du nombre de comparaisons que vous feriez. Un interrupteur de chaîne sera émis sous la forme de deux instructions de commutation distinctes. Le premier fonctionne sur des codes de hachage, il a donc tendance à être un lookupswitch, ce qui donne finalement la O(log n)complexité. Le second est toujours parfait O(1) tableswitch, donc la complexité combinée est toujours O(log n). Une chaîne unique et linéaire de if/else ifdéclarations donnerait une O(n)complexité légèrement pire .

Si vous comparez plus de, disons, trois chaînes, alors a switchest probablement plus lisible et compact. Il fonctionnera probablement mieux, bien que vous ne remarquiez probablement pas de différence, sauf si vous effectuez un grand nombre de comparaisons sur un chemin de code à chaud.


1
Je demandais plutôt pourquoi utiliser un commutateur sur une chaîne plutôt qu'un commutateur sur une énumération. Je considérerais un gros if/elsebloc comme une mauvaise pratique, mais pour le moment, je n'aurais pas beaucoup de raisons d'en utiliser un.
anotherdave

Mais alors une carte en combinaison avec le modèle de commande donnerait même plus de lisibilité avec la même complexité car vous avez le type supplémentaire de la commande
SpaceTrucker

3

Le changement de chaîne peut être utilisé lorsque vos enumvaleurs proviennent de l'extérieur, c'est-à-dire stockées dans une base de données.

Une autre chose notable dans JDK 7 switchest qu'il est beaucoup plus performant que les if-elseconstructions.

Et un bon cas d'utilisation pour des chaînes rapides switchpeut être l'analyse de flux JSON / XML lorsque vous devez effectuer de nombreux commutateurs sur les types de nœuds et d'attributs. Je ne peux pas penser à une meilleure option pour cela.


1
"Le changement de chaîne est irremplaçable lorsque vos valeurs d'énumération proviennent de l'extérieur, c'est-à-dire stockées dans une base de données.": Pouvez-vous nous en dire plus? Les chaînes de l'instruction switch sont codées en dur: dès que les chaînes de la base de données sont modifiées, votre code est obsolète.
Giorgio

Eh bien, vous avez raison - enums peut être utilisé dans ce cas en raison de la nature statique de Java. Quand j'écrivais ceci, je pensais à une Rolebibliothèque de sécurité qui est généralement fournie en classe et ne peut pas être insérée enum. Un autre cas est un code Java / Groovy compilé dynamiquement - dans cette situation, qui est cependant rare, les commutateurs de chaîne peuvent être une meilleure option.
Andrey Chaschev

2

Simplicité

La prise en charge des chaînes dans Switch est utile pour traiter les données sans conversion en énumération ou if-elselogique. Il est parfois plus simple d'activer String.

De la proposition de fonctionnalité à la liste de diffusion JDK 7 (Project Coin) ( @gnat answer )

introduire une énumération pour ses constantes commutables, une par valeur de chaîne d'intérêt, ajouterait un autre type à un programme sans raison valable ...

Version If-Else

C'est court, mais beaucoup if'ssont difficiles à lire. Et c'est lent.

if (color.equals("red")) {
    System.out.println("Color is Red");
} else if (color.equals("green")) {
    System.out.println("Color is Green");
} else {
    System.out.println("Color not found");
}

Version énumérée

Les énumérations doivent être définies, c'est bien, mais parfois pas nécessaire.

enum Color {RED, GREEN}

Traitement comme d'habitude

try {
    switch (Color.valueOf(color)) {
        case RED:
            System.out.println("Color is Red");
            break;
        case GREEN:
            System.out.println("Color is Green");
            break;
    }
} catch (IllegalArgumentException e) {
    System.out.println("Color not found");
}

JDK 7 - Strings in switch Statements version

Nous pouvons traiter sans convertir ni définir de types supplémentaires.

switch (color) {
    case "red":
        System.out.println("Color is Red");
        break;
    case "green":
        System.out.println("Color is Green");
        break;
    default:
        System.out.println("Color not found");
}

7
Cela ne résout pas la question, cependant: pourquoi utiliseriez-vous des chaînes au lieu d'énumérations ici?
Dave Newton

0

La plupart des améliorations dans n'importe quelle langue visent à rendre le code plus facile à lire. Je préfère le code lisible à la fantaisie tous les jours.

Vous ne le croyez peut-être pas, mais essayez:

public enum JettStaff {
  ADRIAN("Adrian German") {
    public String toString() {
      return name + " (dgerman@indiana.edu)";
    }
  },
  ARJIT("Arjit Sengupta") {
    public String toString() {
      return name + " (asengupt@indiana.edu)";
    }
  },

  // and on for the rest...

  private String name;

  public JettStaff(String n) { this.name = n; }
}

JettStaff x = JettStaff.SUZANNE;
System.out.println(x);

Je ne suis pas clair sur votre exemple de code par rapport à vos commentaires ci-dessus. Vous voulez dire l'Enum comme exemple de quelque chose de difficile à lire?
anotherdave


2
C'est très artificiel; vous prétendez que l'énumération n'aurait pas de champ de messagerie ou que ce ne serait pas une classe.
Dave Newton

4
@ user2860598 Si vous essayez de faire valoir un point, utilisez un exemple pertinent. Il n'aborde pas non plus le fait de doigter une constante de chaîne.
Dave Newton

1
@ user2860598 La réponse que vous avez liée dit qu'il y a été introduit et qu'auparavant ils pouvaient être "approximés" avec un Enum. Mon point était que l'utilisation d'Enum semble toujours préférable, même avec leur introduction.
anotherdave

0

Les énumérations sont excellentes et vous devez les utiliser à la place des chaînes lorsque vous en avez la possibilité. Mais il y a des moments où vous ne pouvez tout simplement pas, par exemple lorsque vous devez travailler avec un objet externe venant de l'extérieur de Java. Imaginez que vous devez analyser quelque chose. Comme la réponse du serveur, la configuration, le fichier journal ou quelque chose de similaire: vous avez un tas d'options que vous recherchez et il n'y a aucun moyen de les énumérer. Donc, en Java <7, vous seriez coincé avec un tas de

  if (something.equals("foo")) {
    // foo processing
  } else 
  if (something.equals("bar")) {
   // bar processing
  }

Vous pouvez toujours utiliser des énumérations dans ce cas en essayant simplement de les obtenir par des noms et / ou en fournissant une routine String-> Enum personnalisée, mais parfois ce n'est pas possible ou tout simplement pas pratique (c'est-à-dire lorsque vous devez créer trop d'énumérations)

TLDR : vous devez absolument utiliser Enums lorsque vous travaillez uniquement avec du code Java mais ce n'est pas toujours possible avec des objets externes. J'espère que mon explication a du sens.


Si vous avez affaire à des données externes et que vous en savez déjà assez pour savoir ce dont vous avez besoin dans vos ifinstructions, vous devriez quand même les résumer , ce qui signifie que vous pouvez toujours utiliser des énumérations ou un modèle de commande, etc.
Dave Newton

@DaveNewton oui, vous pouvez toujours utiliser des énumérations mais comme je l'ai dit dans ma réponse, parfois ce n'est pas pratique comme dans le cas où vous finiriez par créer une combinaison d'énumérations à utiliser une seule fois dans votre code lors de l'analyse.

@dimoniy Mais si vous deviez créer des centaines de valeurs Enum, cela ne signifierait-il pas qu'avec une alternative de commutateur, vous devriez avoir des centaines de déclarations de cas? S'il y a autant de variables, je préférerais certainement la sécurité de type des énumérations.
anotherdave

0

Je ne suis pas d'accord avec l'opinion qu'il s'agit d'un code plus propre et lisible lorsque vous l'utilisez Stringsdans des instructions switch et pensez que c'est une mauvaise pratique de programmation. Si vous changez la valeur que vous utilisez pour stocker, vous devez la changer à chaque changement ou à toute occurrence if-elseif. Ce n'est pas bon car vous mettez des valeurs codées en dur à chaque bir de votre code. Qu'allez-vous faire si un jour vous décidez de modifier l'une de ces valeurs codées en dur? Rechercher et remplacer chaque copie de celui-ci?

Si vous avez des valeurs codées en dur que vous faites des instructions if-elseif, l'utilisation de valeurs primitives constantes pour elles est bien meilleure avant Java 1.5 simplement parce qu'elle apporte une sécurité de type.

OK, il y aura des situations où vous obtiendrez des valeurs de chaîne (à partir de la requête HTTP, des fichiers, etc.) et les convertir en valeurs primitives est un problème. Mais Enumje fais du bon travail à ce stade. Parce que lorsque vous souhaitez modifier la valeur que vous stockez dans Enum, changez-la simplement lorsque vous déclarez. Il n'est pas nécessaire de changer quoi que ce soit d'autre dans votre code. (Vous devez bien sûr modifier les valeurs stockées ailleurs).

Bien sûr, si vous implémentez simplement un code sale et paresseux, c'est parfait. Vous ne voulez pas impliquer de coder beaucoup de Enums, mais dans un logiciel complexe à grande échelle qui vous tuera.


-1

Si vous savez quelles informations arrivent et qu'elles ne peuvent être que de 5 états, utilisez un Enum. Cependant, si les états possibles peuvent être supérieurs à 9000 et que vous n'en avez besoin que de 42, il est préférable d'utiliser un commutateur car vous ne voulez pas taper tous ces états.

Un Enum a tendance à être le choix de la plupart dans la plupart des circonstances, sauf lorsque les états possibles sont inconnus ou qu'il y en a beaucoup et que vous ne vous souciez que de quelques-uns.

Mais pourquoi l'ont-ils introduit maintenant? C'était juste un changement qui permettait un code plus propre.

Dans 1.5, ils vous permettaient également de créer des corps personnalisés pour Enums.


Mais n'attribueriez-vous pas simplement les 8958 autres valeurs possibles à l'état Enum unique?
anotherdave

@anotherdave C'est là que defaultdans switchentre en jeu. Je ne sais pas que vous pouvez avoir un état par défaut avec Enum, à moins que vous ne fassiez un état par défaut, mais ce code est tout simplement gonflé alors que a switchest beaucoup plus propre à utiliser.

3
Il semble étrange de dire qu'un UNKNOWNétat sur un Enum est gonflé, mais pas un defaultboîtier sur un commutateur.
anotherdave
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.