Pourquoi n'y a-t-il pas de String.Empty en Java?

260

Je comprends que chaque fois que je tape le littéral de chaîne "", le même objet String est référencé dans le pool de chaînes.

Mais pourquoi l'API String n'inclut-elle pas un public static final String Empty = "";, donc je pourrais utiliser des références à String.Empty?

Cela permettrait d'économiser sur le temps de compilation, à tout le moins, car le compilateur saurait référencer la chaîne existante, et n'aurait pas à vérifier si elle avait déjà été créée pour être réutilisée, non? Et personnellement, je pense qu'une prolifération de littéraux de chaîne, en particulier de minuscules, dans de nombreux cas est une "odeur de code".

Y avait-il donc une raison de Grand Design derrière aucun String.Empty, ou les créateurs de langage n'ont-ils tout simplement pas partagé mes vues?

Tom Tresansky
la source
5
Aidanc: Je pense qu'il veut dire des situations où vous faites des choses comme outputBlah = "", et il préfère probablement something == String.Emptyplus something.Length > 0aussi bien (vous sautez un chèque nul.)
Skurmedel
2
@Aidanc - Il cherchait un "membre vide" comme Collections.EMPTY_SET , pas une fonction pour vérifier la chaîne "vide".
Tim Stone
2
@Aidanc: Ce qui a inspiré cela est en fait 'TextBox.setText ("");'.
Tom Tresansky
3
Il y a une String.isEmpty()fonction ... pourquoi voudriez-vous String.EMPTY?
Buhake Sindi
8
String.isEmpty()ne renvoie pas de chaîne vide.
Steve Kuo

Réponses:

191

String.EMPTYest de 12 caractères et de ""deux, et ils feraient tous deux référence exactement à la même instance en mémoire lors de l'exécution. Je ne sais pas vraiment pourquoiString.EMPTY gagnerait du temps de compilation, en fait je pense que ce serait ce dernier.

Particulièrement compte tenu du fait que les Strings sont immuables, ce n'est pas comme si vous pouviez d'abord obtenir une chaîne vide et effectuer certaines opérations dessus - il vaut mieux utiliser un StringBuilder(ouStringBuffer si vous voulez être thread-safe) et le transformer en une chaîne.

Mise à jour
De votre commentaire à la question:

Qu'est-ce qui a inspiré cela? TextBox.setText("");

Je pense qu'il serait tout à fait légitime de fournir une constante dans votre classe appropriée:

private static final String EMPTY_STRING = "";

Et puis référencez-le comme dans votre code

TextBox.setText(EMPTY_STRING);

De cette façon, au moins, vous êtes explicite que vous voulez une chaîne vide, plutôt que vous avez oublié de remplir la chaîne dans votre IDE ou quelque chose de similaire.

Noel M
la source
14
Je vous attribuerai toujours +1, mais je me sens sale parce que vous avez mentionné StringBuildersans parler du fait que neuf fois sur dix, il est totalement inapproprié d'utiliser StringBuilderplutôt que de concaténer.
Randolpho
85
J'ai tendance à préférer string.empty, principalement parce qu'il est plus explicite. De plus, il existe des situations où il peut être plus difficile de différencier visuellement "" et des choses comme "" ". En fin de compte, comme d'autres l'ont remarqué, ce n'est qu'une de ces choses de style dénuées de sens qui nous donnent du fourrage pour discuter quand nous nous ennuyons avec un vrai travail. =)
JohnFx
@Nodel M: En ce qui concerne le temps de compilation, je suppose que s'il y a 2 littéraux de chaîne définis dans 2 fichiers source différents avec la même valeur de chaîne, lorsque le compilateur atteint le 2e, il doit faire une sorte de vérification pour comprendre " hé, je connais déjà cette chaîne depuis ici ". Je ne suis certes pas un expert du compilateur java, mais comment cela ne pourrait-il pas être le cas? Et je pense que sauter cette vérification entraînerait une amélioration minuscule des temps de compilation.
Tom Tresansky
@Tom - Je crois que l'internement de chaînes est effectué au moment de l'exécution, pas lors de la compilation, donc en fait, si vous avez la chaîne vide comme constante dans un autre fichier, le compilateur doit référencer cette classe pour se résoudre au littéral String.
Noel M du
1
@Randolpho Lorsque vous utilisez la concaténation de chaînes, vous utilisez en fait un StringBuilder sous le capot.
whiskeysierra
133

Utilisation org.apache.commons.lang.StringUtils.EMPTY

jade
la source
30
Semble beaucoup plus agréable et plus facile à lire qu'un "" vide. J'espère que ce n'est pas seulement moi.
Lakatos Gyula
2
@LakatosGyula - Je pense que ça pourrait être (juste toi). Les programmeurs Java compétents n'ont aucun problème à lire ""... et la plupart s'opposeraient probablement fortement à l'utilisation de, EMPTYsauf dans des situations spécifiques où EMPTYa une signification spécifique au domaine. (Et dans de tels cas, il y a probablement un nom plus approprié.)
Stephen C
14
@LakatosGyula Ce n'est pas seulement vous. Je suis passé du développement Java au développement .NET, et String.Empty était une fonctionnalité que j'étais heureux de trouver dans le cadre. J'aime sa nature explicite par-dessus un ensemble vide de citations.
yohohoho
64
@StephenC Quand je vois un "" vide, la première chose me vient à l'esprit que c'est un bug, quelqu'un n'a pas terminé la fonction, etc. Avec String.EMPTY, je sais exactement que le développeur avait l'intention de retourner une chaîne vide.
Lakatos Gyula
1
Aussi utile pour toutes ces fois où le linter dit "utilisez une constante nommée au lieu de bla bla bla". Chaque programmeur sait que "" n'est pas magique, mais ne pas avoir à l'expliquer au client est mieux.
LizH
28

Si vous souhaitez comparer avec une chaîne vide sans vous soucier des valeurs nulles, vous pouvez procéder comme suit.

if ("".equals(text))

En fin de compte, vous devez faire ce que vous pensez être le plus clair. La plupart des programmeurs supposent que "" signifie une chaîne vide, pas une chaîne dans laquelle quelqu'un a oublié de mettre quoi que ce soit.

Si vous pensez qu'il existe un avantage en termes de performances, vous devez le tester. Si vous ne pensez pas que cela vaut la peine d'être testé par vous-même, c'est une bonne indication que cela n'en vaut vraiment pas la peine.

Il vous semble que vous essayez de résoudre un problème qui a été résolu lorsque le langage a été conçu il y a plus de 15 ans.

Peter Lawrey
la source
1
Je suis assez tard pour la fête mais, comme les chaînes Java sont immuables, je pense que toutes les chaînes vides dans une JVM ne sont que des références différentes au même objet String. Donc, tout simplement ce qui suit est également correct: if ("" == text)
Ajoy Bhatia
12
@AjoyBhatia Le problème est que vous pouvez créer de nouvelles chaînes vides. if ("" == new String())c'est faux. Un meilleur testif(text.isEmpty())
Peter Lawrey
1
@AjoyBhatia - Uniquement si les chaînes sont internées. stackoverflow.com/questions/10578984/what-is-string-interning
Davor
9

Si vous voulez vraiment une constante String.EMPTY, vous pouvez créer une classe finale statique utilitaire nommée "Constantes" (par exemple) dans votre projet. Cette classe conservera vos constantes, y compris la chaîne vide ...

Dans la même idée, vous pouvez créer des constantes ZERO, ONE int ... qui n'existent pas dans la classe Integer, mais comme je l'ai commenté, ce serait pénible d'écrire et de lire:

for(int i=Constants.ZERO; ...) {
    if(myArray.length > Constants.ONE) {
        System.out.println("More than one element");
    }
}

Etc.

Benoit Courtine
la source
8

Apache StringUtils résout également ce problème.

Échecs des autres options:

  • isEmpty () - non null safe. Si la chaîne est nulle, lance un NPE
  • length () == 0 - encore une fois pas nul. Ne prend pas non plus en compte les chaînes d'espaces.
  • Comparaison avec la constante EMPTY - Peut ne pas être null safe. Problème d'espace blanc

Granted StringUtils est une autre bibliothèque à déplacer, mais elle fonctionne très bien et économise beaucoup de temps et de tracas pour vérifier les valeurs nulles ou gérer les NPE avec élégance.

Freiheit
la source
3
alors ... il semble que la seule option sûre est la condition Yoda terrible: "".equals(s)?
Lie Ryan
8

Ne vous contentez pas de dire que "le pool de mémoire des chaînes est réutilisé sous la forme littérale, cas fermé". Ce que les compilateurs font sous le capot n'est pas le sujet ici. La question est raisonnable, surtout compte tenu du nombre de votes positifs qu'elle a reçus.

Il s'agit de la symétrie , sans elle, les API sont plus difficiles à utiliser pour les humains. Les premiers SDK Java ignoraient notoirement la règle et maintenant c'est un peu trop tard. Voici quelques exemples au-dessus de ma tête, n'hésitez pas à intégrer votre exemple "préféré":

  • BigDecimal.ZERO, mais pas AbstractCollection.EMPTY, String.EMPTY
  • Array.length mais List.size ()
  • List.add (), Set.add () mais Map.put (), ByteBuffer.put () et n'oublions pas StringBuilder.append (), Stack.push ()
Slawomir
la source
Même si vous avez nommé le paramètre List length (), vous avez toujours besoin des parenthèses car c'est une méthode. Array.length est une variable finale publique, qui ne fonctionne que parce que les tableaux sont immuables. Vous auriez donc toujours Array.length et List.length (). Je dirais que c'est plus déroutant et sujet à erreur. Quant à .append () et .push (), alors qu'ils effectuent des tâches similaires, je pense qu'ils ont été correctement nommés. Ajouter la chaîne est exactement ce que vous faites, mais vous n'ajoutez pas de pile, vous poussez et popz des valeurs. Et StringBuilder.push () impliquerait StringBuilder.pop (), ce qui n'est pas possible.
Craig Parton
Venant de modèles / génériques, des interfaces cohérentes aident également avec les algorithmes. Si un algorithme a besoin d'une longueur de collection, la longueur (T) ou T.length () est tout ce dont nous nous soucions. De même, l'ajout à la fin d'une pile, d'une liste ou d'une chaîne peut être effectué par un add () ou un append () universel. Vous avez mentionné que le tableau en Java est de type immuable / intégré avec une propriété de longueur exposée. C'est bien, cela ne signifie pas que le compilateur ne peut pas gérer ou générer du code pour length (T) ou T.length (). Kotlin génère un certain nombre de méthodes intrinsèques pour divers cas.
Slawomir
Mais une méthode length () nommée de manière cohérente nous permet uniquement de vérifier la longueur. Est-ce utile? Si votre objectif est d'abstraire des listes et des tableaux pour les rendre utilisables d'une manière ou d'une autre via une interface, vous avez également besoin d'un moyen cohérent pour lire ou écrire des données. Alors maintenant, vous devez générer les méthodes get (), set () et add (). Essentiellement, vous créez une vue de liste moins fonctionnelle du tableau. Puisque Arrays.asList () est disponible, facile à utiliser et léger, pourquoi réinventer la roue? Les tableaux, les listes, les StringBuilders et les piles ont tous un objectif spécifique. Il semble préférable de concevoir votre interface pour utiliser le meilleur ajustement.
Craig Parton
5

Tous ceux "" littéraux sont le même objet. Pourquoi rendre toute cette complexité supplémentaire? C'est juste plus long à taper et moins clair (le coût pour le compilateur est minime). Étant donné que les chaînes de Java sont des objets immuables, il n'est jamais nécessaire de les distinguer, sauf peut-être pour des raisons d'efficacité, mais avec le littéral de chaîne vide, ce n'est pas un gros problème.

Si vous voulez vraiment une EmptyStringconstante, faites-la vous-même. Mais il ne fera qu'encourager un code encore plus verbeux; il n'y aura jamais aucun avantage à le faire.

Associés Donal
la source
27
x = String.Emptytransmet l'intention mieux que x = "". Ce dernier pourrait être une omission accidentelle. Dire qu'il n'y a jamais aucun avantage est incorrect.
Jeffrey L Whitledge
@Jeffrey: Je ne pense pas être particulièrement d'accord. C'est une de ces choses où il n'y a pas de règle stricte et rapide, je suppose.
Donal Fellows
Oui, il est important de souligner que le compilateur java vérifie si des littéraux de chaîne existent déjà avant de créer une nouvelle instance dans le pool de chaînes.
rds
1
@Jeffrey - sachant qu'il s'agit d'une discussion très ancienne et subjective. x = String.Emptytransmet l'intention, vrai. Mais supposons que le langage fournisse une constante String.Empty, lorsque vous rencontrez, x = ""vous en savez toujours autant sur l'intention que s'il n'y avait pas une telle constante. Vous auriez besoin de garantir que tous les endroits du code Java du monde où une chaîne vide était intentionnelle n'utilisent pas ""afin d'obtenir le gain d'informations que vous mentionnez. Ironiquement, C # utilise une constante et encourage son utilisation, donc comme je l'ai dit, je sais que c'est une discussion très d'opinion.
chiccodoro
@chiccodoro - Oui, c'est vrai. C'est pourquoi le littéral de chaîne vide ""doit être illégal, pour exclure les accidents. Je blague!
Jeffrey L Whitledge
4

Pour ajouter à ce que Noel M a déclaré, vous pouvez regarder cette question, et cette réponse montre que la constante est réutilisée.

http://forums.java.net/jive/message.jspa?messageID=17122

Les constantes de chaîne sont toujours "internées", il n'y a donc pas vraiment besoin d'une telle constante.

String s=""; String t=""; boolean b=s==t; // true
James Black
la source
1
le lien est mort.
Dieter
3

Je comprends que chaque fois que je tape le littéral String "", le même objet String est référencé dans le pool String.
Il n'y a pas une telle garantie. Et vous ne pouvez pas vous y fier dans votre application, c'est à jvm de décider.

ou les créateurs de la langue n'ont-ils tout simplement pas partagé mes opinions?
Oui. Pour moi, cela semble chose de très faible priorité.

Nikita Rybak
la source
6
Il n'y a aucune garantie de ce type ... Eh bien, le JLS déclare que cela devrait être le cas.
Tim Stone
@Tim Non, sauf si vous effectuez un appel «interne». Il est facile de construire deux grandes chaînes égales par programme et de vérifier.
Nikita Rybak
@Tim Par exemple, répétez a + = "a"; 100 fois, faites de même avec b et vérifiez.
Nikita Rybak
5
Vous avez raison, mais ce que vous avez décrit n'est pas un littéral de chaîne, ni une expression dont le résultat peut être garanti au moment de la compilation (comme String username = "Bob" + " " + "Smith";). Les chaînes créées par programmation n'ont aucune garantie d'être internées, sauf si vous appelez explicitement intern()comme vous l'avez indiqué. Le scénario de l'OP décrit l'utilisation du littéral de chaîne vide ""dans tout le code, ce qui est un cas où l'internement automatique se produirait.
Tim Stone
@Tim String a = ""; for(int i = 0; i < 100; i++) {a += "a";} String b = ""; for(int i = 0; i < 100; i++) {b += "b";} a.intern(); b.intern();Maintenant, le aet bpointez sur le même emplacement de mémoire dans PermGen. Voir cet article
1ac0
1

Réponse tardive, mais je pense que cela ajoute quelque chose de nouveau à ce sujet.

Aucune des réponses précédentes n'a répondu à la question d'origine. Certains ont tenté de justifier l'absence de constante, tandis que d'autres ont montré comment nous pouvons faire face à l'absence de constante. Mais personne n'a fourni de justification convaincante au bénéfice de la constante, de sorte que son manque n'est toujours pas correctement expliqué.

Une constante serait utile car elle éviterait que certaines erreurs de code ne passent inaperçues.

Supposons que vous ayez une grande base de code avec des centaines de références à "". Quelqu'un en modifie un en faisant défiler le code et le change en "". Un tel changement aurait de fortes chances de passer inaperçu en production, auquel cas il pourrait provoquer un problème dont la source sera difficile à détecter.

OTOH, une constante de bibliothèque nommée EMPTY, si elle est sujette à la même erreur, générerait une erreur de compilation pour quelque chose comme EM PTY.

Définir sa propre constante est encore mieux. Quelqu'un pourrait encore modifier son initialisation par erreur, mais en raison de sa large utilisation, l'impact d'une telle erreur serait beaucoup plus difficile à passer inaperçu qu'une erreur dans un cas d'utilisation unique.

C'est l'un des avantages généraux que vous obtenez en utilisant des constantes au lieu de valeurs littérales. Les gens reconnaissent généralement que l'utilisation d'une constante pour une valeur utilisée dans des dizaines d'endroits vous permet de mettre facilement à jour cette valeur en un seul endroit. Ce qui est moins souvent reconnu, c'est que cela empêche également que cette valeur ne soit accidentellement modifiée, car un tel changement apparaîtrait partout. Donc, oui, "" est plus court que VIDE, mais VIDE est plus sûr à utiliser que "".

Donc, pour revenir à la question d'origine, nous ne pouvons que spéculer que les concepteurs de langage n'étaient probablement pas conscients de cet avantage de fournir des constantes pour les valeurs littérales qui sont fréquemment utilisées. Espérons que nous verrons un jour des constantes de chaînes ajoutées en Java.

Laurentiu Cristofor
la source
-16

Pour ceux qui prétendent ""et String.Emptysont interchangeables ou c'est ""mieux, vous avez très tort.

Chaque fois que vous faites quelque chose comme myVariable = ""; vous créez une instance d'un objet. Si l'objet String de Java avait une constante publique EMPTY, il n'y aurait qu'une seule instance de l'objet ""

Par exemple: -

String.EMPTY = ""; //Simply demonstrating. I realize this is invalid syntax

myVar0 = String.EMPTY;
myVar1 = String.EMPTY;
myVar2 = String.EMPTY;
myVar3 = String.EMPTY;
myVar4 = String.EMPTY;
myVar5 = String.EMPTY;
myVar6 = String.EMPTY;
myVar7 = String.EMPTY;
myVar8 = String.EMPTY;
myVar9 = String.EMPTY;

10 (11 y compris String.EMPTY) Pointeurs vers 1 objet

Ou: -

myVar0 = "";
myVar1 = "";
myVar2 = "";
myVar3 = "";
myVar4 = "";
myVar5 = "";
myVar6 = "";
myVar7 = "";
myVar8 = "";
myVar9 = "";

10 pointeurs vers 10 objets

Ceci est inefficace et tout au long d'une grande application, peut être significatif.

Le compilateur Java ou l 'exécution est peut - être suffisamment efficace pour pointer automatiquement toutes les instances de "" vers la même instance, mais il se peut qu'il ne le fasse pas et nécessite un traitement supplémentaire pour effectuer cette détermination.

Antony Booth
la source
9
Incorrect, selon stackoverflow.com/questions/1881922/… , la chaîne "" sera réutilisée à partir du pool de chaînes.
RealHowTo
1
J'ai déclaré qu'il pourrait réutiliser le même objet et si c'est le cas, il est toujours moins efficace, car il doit trouver cet objet (dans le pool de chaînes), alors comment me trompe-je? Quoi qu'il en soit, il existe plusieurs raisons pour lesquelles String.Empty est supérieur, y compris la prévention des erreurs telles que myVar = ""; et la lisibilité ainsi que l'amélioration des performances que j'ai déjà indiqué. Il est recommandé d'utiliser des constantes au lieu de créer des littéraux de chaîne, si ce n'est pour aucune autre raison; il est plus facile de maintenir le code.
Antony Booth
1
Je doute que votre argument de performance soit valide car le JLS indique qu'une constante sera traitée comme littérale au moment de la compilation ( docs.oracle.com/javase/specs/jls/se7/html/jls-3.html#jls-3.10. 5 ). La lisibilité est un meilleur argument.
RealHowTo
3
@AntonySmith - Je suppose que vous devez étudier Java un peu plus ou peut-être connaissez-vous maintenant votre erreur. Les chaînes Java sont immuables et dans un pool. Il n'y a donc qu'un seul objet String pour "" dans une machine virtuelle Java, quel que soit le nombre de fois où il se trouve dans le code. Vous pouvez vérifier si une chaîne est vide en faisantif (text == "")
Ajoy Bhatia
2
Faux. Ce commentaire doit être supprimé.
Elad Tabak