web-dev-qa-db-fra.com

Appeler est égal au littéral de chaîne

Je venais juste de ranger un peu mon code et il y avait cette pièce:

String saving = getValue();
if(saving != null && saving.equals("true")){
   // do something
}

Ensuite, j'ai pensé faire l'inverse pour supprimer la vérification de null:

if("true".equals(saving)){
   // do something
}

Cela fonctionne certainement, mais est-ce sûrde le faire? Je veux dire que les littéraux de chaîne sont stockés dans un pool commun, alors que les objets string créés par new sont sur le tas. Mais les chaînes du pool constant sont aussi des objets, n'est-ce pas?

Mais cela ne semble toujours pas être la bonne chose à faire, même si cela raccourcit le code.

22
Kuba Spatny

C'est sûr - et comme vous l'avez vu, un bon moyen d'éviter les pointeurs nuls.

Vous mentionnez l'utilisation de new pour Strings. De nombreux outils d'analyse de code statique Java recommandent de toujours utiliser des littéraux au-dessus de new String("foo");.

Modifier:

Si vous le souhaitez, vous pouvez simplement utiliser:

if (Boolean.valueOf(saving)) {
    ...
}

Selon les docs , passer null retournera false.

22
jakson

Afin d’assurer un ensemble de réponses parfaitement équilibré à cette question, je souhaiterais émettre un avis différent.

Je pense que ce mécanisme est stupide.

Si vous avez une null, vous devriez le savoir dès que cela se produit - le cacher ne fera que reporter sa découverte. Si la null n'est pas une exception, remplacez-la par quelque chose d'autre.

Cette approche renforcera votre code avec ce qu'on appelle programmation défensive où vos erreurs sont découvertes dès que possible plutôt que masqué jusqu'à ce que tout s'effondre.

En résumé - NullPointerException est votre ami. Vous devriez l'utiliser pour trouver des erreurs dans votre code. Il est très facile d’utiliser un Empty objet tel que Collections.emptySet() une fois que vous avez déterminé que null n’est pas une exception.

L'utilisation de la technique Yoda par habitude cachera inévitablement des erreurs que vous ne voulez pas cacher. Non son utilisation exposera les erreurs beaucoup plus tôt. Pour moi, c'est un argument suffisant pour ne pas l'utiliser - jamais.

Pour moi - en utilisant

if(saving != null && saving.equals("true")){

signifie que je veux réellement permettre à savings d'être null et que c'est une situation acceptable - en utilisant

if("true".equals(saving)){

cache simplement ce choix délibéré d’une manière qui pourrait devenir une mauvaise habitude.

21
OldCurmudgeon

Cela s'appelle des conditions yoda (mettre une constante avant une variable dans une comparaison) peut être considéré comme une mauvaise pratique, peut-être pour quelqu'un beaucoup moins lisible (comme moi). 

Mais parfois, utiliser la condition yoda rend le code plus "compréhensible" -> vous n'avez pas besoin de mettre un contrôle null supplémentaire devant celui-ci et cela différencie efficacement le bloc de code du cas où la valeur null est fortement interdite.

8
Simon Dorociak

Je suis en désaccord avec certaines des réponses. Parfois, vous do voulez savoir si votre variable est null. Cela pourrait indiquer que quelque chose de mauvais se passe dans votre code et que vous souhaitiez peut-être reconsidérer votre logique. 

Je n'aime pas faire if("someString".equals(myString)); parce que je fais veux savoir si myString est null et peut-être le gérer ou changer ma logique pour éviter de telles situations.

Imaginez que vous ayez un tableau d'objets mal calculé en raison d'un bogue:

myStrings = {..., ..., null, null, ...};

Ensuite, vous voulez effectuer quelques opérations sur les objets du tableau, et vous aurez:

if("myString".equals(myObjArray[i])) { ... } 

Vous n'obtiendrez pas NullPointerException et vous penserez que vous avez effectué l'opération sur tous les objets du tableau .. Et vous ne saurez jamais que vous l'avez mal calculé car vous avez "masqué" l'exception. Considérant que si vous avez fait:

if(myObjArray[i].equals("myString")) { ... } 

Vous obtiendrez unNPEet vous saurez que quelque chose ne va pas dans le tableau .. et vous voudrez peut-être résoudre ce problème ou le gérer d’une autre manière.

8
Maroun
if("true".equals(saving)){
   // do something
}

C'est très sûr et c'est une bonne pratique. La chaîne "true" ne sera jamais nulle. Donc, vous ne comparerez jamais votre chaîne à null. Ce morceau de code est parfaitement bien

5
k4sia

Le format qui met le littéral en premier évite le NPE potentiel et sera toujours faux pour "literal".equals(null).

En effet, une expression "littérale" always correspond à un objet String (et n'est donc jamais nulle) et String.equals(obj) vérifie si l'objet other est null (via asinstanceof). Un objet est un objet - inutile de s’inquiéter du "tas".

Il est judicieux d’avoir une garde nulle dans une implémentation d’égal à égal as null.equals(null) est not admissible: "La méthode equals implémente une relation d’équivalence sur non-nulle référence à un objet"

Voici le String.equals le source (pour OpenJDK):

public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    if (anObject instanceof String) {
        // ..
    }
    return false;
}
4
user2864740

Désolé mais je ne peux pas être d'accord sur cette question. 

Si vous utilisez d'abord la constante, vous supportez des structures qui masquent les erreurs de programmation. Et on ne devrait produire que du code soit 

  1. ajouter des fonctionnalités,
  2. corriger une erreur de programmation
  3. ou essayer de supporter des structures pour éviter les erreurs de programmation (comme modèles de conception).

En plus, vous avez une affirmation faible sur la variable. Le code suivant est toujours obligé de vérifier également les valeurs NULL. 

Si vous devez gérer des valeurs NULL provenant d'autres modules, votre tâche consiste à les mapper le plus tôt possible dans les représentations appropriées dans votre modèle de domaine. 

Dans votre propre code, évitez la valeur null en tant que paramètre ou valeur renvoyée. Par conséquent, il n'y aura plus de vérification de null requise, le code suggéré étant inclus. 

Vous voyez, ce sujet concerne plus le fait d'éviter NULL que de l'accepter pour vaincre votre code.

2
oopexpert
if ("true".equals(saving))

est parfaitement "sauvegardé" et recommandé par dummy product comme SonarLint et tous les autres conseillers qui établissent cette règle "bien pensée" que votre chef vous demande de suivre.

Je dis stupide et mon explication est la suivante.

Que se passe-t-il si vous avez le code suivant

if (!saving.equals("true"))
    {
    if (saving.length() > 10)
        {
        // do something
        }
    }

Vous pouvez utiliser le code conseillé suivant 

if (!"true".equals(saving))
    {
    if (saving.length() > 10)
        {
        // do something
        }
    }

Mais lorsque votre code est déployé en production, le programme se bloque sur la fonction length() si la variable de sauvegarde n’a pas été initialisée et contient la valeur NULL. 

Vous devez modifier votre code pour éviter la fonction NullPointerException sur equals() mais votre programme renverra une autre fonction NullPointerException sur length()!

La bonne réaction est de cesser d'utiliser Astuce littérale de chaîne et d'analyser le code pour trouver une solution parfaite comme dans l'exemple suivant.

if (saving != null)
    {
    if (!saving.equals("true"))
        {
        if (saving.length() > 10)
            {
            // do something
            }
        }
    }

ou

if (saving == null) saving = "";

if (!saving.equals("true"))
    {
    if (saving.length() > 10)
        {
        // do something
        }
    }

C'est peut-être commenté, mais si vous utilisez Java pour la programmation, c'est le prix à payer.

L'utilisation de la méthode String literal equals () pour éviter NullPointerException présente les inconvénients suivants

  1. la solution est délicate
  2. le code n'est pas naturellement lisible pour l'homme
  3. l’égalité ne plantera pas mais une autre partie du programme continuera à planter
  4. le code devient rapidement difficile à lire si cette astuce est utilisée pour pour des fonctions inférieures () et supérieures () (exemple: if ('USA'.greater (sCode)))
  5. donner une fausse impression que le code est sûr
1
schlebe

Non seulement sûr mais c’est aussi un moyen préféré de résoudre ce problème.

0
Marcin Szymczak