web-dev-qa-db-fra.com

Pourquoi "else" est-il rarement utilisé après "si x retourne"?

Cette méthode:

boolean containsSmiley(String s) {
    if (s == null) {
        return false;
    }
    else {
        return s.contains(":)");
    }
}

peut être écrit de manière équivalente:

boolean containsSmiley(String s) {
    if (s == null) {
        return false;
    }

    return s.contains(":)");
}

D'après mon expérience, la seconde forme est plus fréquente, en particulier dans les méthodes plus complexes (où il peut y avoir plusieurs points de sortie), et il en va de même pour "lancer" et "retour". Cependant, la première forme rend plus explicite la structure conditionnelle du code. Y a-t-il des raisons de préférer l'une à l'autre?

(En rapport: Une fonction devrait-elle avoir une seule déclaration de retour? )

57
Todd Owen

D'après mon expérience, cela dépend du code. Si je «garde» contre quelque chose, je ferai:

if (inputVar.isBad()) {
    return;
}

doThings();

Le fait est clair: si cette affirmation est fausse, je ne veux pas que la fonction continue.

D'autre part, il y a des fonctions avec plusieurs options, et dans ce cas, je l'écrirais comme ceci:

if (inputVar == thingOne) {
    doFirstThing();
} else if (inputVar == secondThing) {
    doSecondThing();
} else {
    doThirdThing();
}

Même si cela pourrait être écrit comme:

if (inputVar == thingOne) {
    doFirstThing();
    return;
}
if (inputVar == thingTwo) {
    doSecondThing();
    return;
}
doThingThree();
return;

Cela dépend vraiment de la manière la plus claire de montrer ce que fait le code (pas nécessairement quel bit de code est le plus court ou le moins indenté).

65
Brendan Long

Dans ce cas, la variable else serait redondante et créerait une indentation supplémentaire inutile pour le code principal de la fonction.

86
Delan Azabani

Ceci est un modèle appelé Guard Clause . L'idée est de procéder à toutes les vérifications initiales afin de réduire les conditions imbriquées afin d'améliorer la lisibilité.

Du lien:

double getPayAmount() {
    double result;
    if (_isDead) {
        result = deadAmount();
    } else {
        if (_isSeparated) {
            result = separatedAmount();
        } else {
            if (_isRetired) {
                result = retiredAmount();
            } else {
                result = normalPayAmount();
            }
        }
    }

    return result;
}

En utilisant la clause de garde, vous obtiendrez le résultat suivant:

double getPayAmount() {
    if (_isDead) return deadAmount();
    if (_isSeparated) return separatedAmount();
    if (_isRetired) return retiredAmount();

    return normalPayAmount();
};
32
Eugene Yokota

Vous verrez cela partout:

if (condition) {
    return var;
}
// by nature, when execution reaches this point, condition can only be false,
// therefore, the else is unnecessary
return other_var;

La plupart du temps, l'ajout d'une clause else n'est pas seulement inutile dans ce cas, mais souvent, il obtient optimisé à distance par le compilateur.

Pensez à la façon dont l'ordinateur conçoit ce code (en termes de code machine, simplifié ici en pseudocode à des fins de démonstration):

0x00: test [condition]
0x01: if result of test was not true, goto [0x04]
0x02: Push [var] onto stack
0x03: goto [0x05]
0x04: Push [other_var] onto stack
0x05: return from subroutine

Le code (là encore, il s’agit d’un pseudocode et non d’Assembly) agirait exactement de la même manière pour un if/then/else conditionnel.

Pour de nombreuses personnes, il est considéré comme une pratique douteuse et source de confusion d’avoir plusieurs points de sortie possibles pour une fonction, puisqu’un programmeur doit penser à tous les chemins possibles dans son code. Une autre pratique est la suivante:

return (condition) ? var : other_var;

Cela simplifie le code et ne crée aucun nouveau point de sortie.

8
amphetamachine

Je préfère l'écrire comme ça:

boolean containsSmiley(String s) {
    return s != null && s.contains(":)");
}
7
ChaosPandion

Je préférerais la première option, car elle est plus lisible par l'homme.

Par analogie, comparez les 2 phrases suivantes: "Si aujourd'hui il pleut, prenez un parapluie, sinon prenez des lunettes de soleil." et "S'il pleut aujourd'hui, prenez un parapluie, prenez des lunettes de soleil". La première phrase correspond au premier bloc de code de la question, la seconde à la seconde. Le premier est beaucoup plus clair et lisible, n'est-ce pas?

4
yaskovdev

Comme pour toute "discussion" sur les styles de codage, il n'y a pas de réponse correcte. Je préfère appliquer ces considérations:

  1. Le code fonctionne-t-il comme prévu dans toutes les situations? (Principe de moindre surprise)

  2. Le prochain développeur (moi-même ou quelqu'un d'autre) peut-il comprendre ce qu'il fait et pourquoi?.

  3. À quel point le code est-il fragile en ce qui concerne le changement?.

  4. C'est simple comme il se doit et pas plus. C'est à dire. pas de sur ou sous ingénierie.

Une fois que je suis heureux d'avoir satisfait à ce qui précède, le reste tombe généralement dans les règles.

4
drekka

Quelqu'un d’autre l’a probablement déjà noté, mais je vous déconseille d’utiliser des valeurs null en général lorsque des chaînes sont attendues. Si vous voulez vraiment que la vérification empêche quelqu'un de passer des valeurs NULL, vous pouvez utiliser des assertions (au moment du dev) ou des tests unitaires (deploy):

boolean containsSmiley(String s) {
    assert s != null : "Quit passing null values, you moron.";
    return s.contains(":)");
}

Je suis passé à une règle générale: Jamais. Déjà. transmettez des valeurs null, à moins qu'un appel d'API externe ne le demande explicitement. Deuxièmement: si une méthode externe peut renvoyer des valeurs NULL, remplacez-la par une valeur raisonnable non-NULL (telle qu'une chaîne vide) ou ajoutez une vérification soignée. J'en ai assez des chèques if (thing == null) répétitifs.

Mais c'est un peu hors sujet. J'aime mettre de courtes conditions sur les clauses top et guard, et supprimer les elses si le déroulement du programme indique qu'il n'y parviendra jamais.

3
fwielstra

Parce que c'est mieux. Vous savez que vous pouvez également utiliser '{' '}' pour créer plusieurs niveaux d'imbrication, mais personne ne le fait vraiment pour rien.

2
user392942

La else est redondante. De plus, certains IDE (Eclipse) et outils d'analyse (peut-être FindBugs) peuvent signaler cela comme un avertissement ou une erreur. Dans ce cas, les programmeurs sont susceptibles de le supprimer.

2
Juha Syrjälä

C'est un argument religieux et au bout du compte, cela n'a pas d'importance. Je dirais même que le premier formulaire est plus lisible dans certaines circonstances. Si vous avez de gros morceaux de code dans un if-elseif-elseif-else, il est plus facile de voir à première vue quel est le retour par défaut.

if (s == null) {
    return false;
}
else if (s.Contains(":))")) {
    return true;
}
else if (s.Contains(":-(")) {
    return false;
}

return s.contains(":)");
2
Igor Zevaka

Le rasoir d'Occam est le principe selon lequel "les entités ne doivent pas être multipliées au-delà de la nécessité".

2
ldog

L'instruction if vérifie/applique votre contrat/attente de ne pas recevoir de valeur NULL. Pour cette raison, je préférerais le voir séparé du reste de la fonction, car cela n’a rien à voir avec la logique réelle de ce que vous essayez d’accomplir (bien que ce soit très simple).

Dans la plupart des cas, cependant, je préfère que le code soit aussi explicite que possible dans son intention. Si vous pouvez restructurer quelque chose à propos de votre fonction pour la rendre plus lisible par d'autres, faites-le. En tant que programmeur professionnel, votre objectif devrait être de programmer pour ceux qui doivent maintenir votre code après vous (y compris vous-même 2 ans plus tard ...). Tout ce que vous pouvez faire pour les aider vaut la peine d'être fait.

2
Tim Coker

Je préférerais un point de sortie à plusieurs points de vue maintenance. Le résultat final peut être modifié (ou décoré) à un point de sortie plutôt que n points de sortie.

0
Sushant

La seconde forme si plus simple/plus courte. Cela ne signifie pas toujours plus clair. Je vous suggère de faire ce que vous trouvez le plus clair. Personnellement, j'écrirais.

static boolean containsSmiley(String s) { 
    return s != null && s.contains(":)"); 
} 
0
Peter Lawrey

Car il existe un avertissement facultatif (désactivé par défaut) dans Eclipse si else est utilisé dans une telle situation;).

0
Ha.

La première forme est simplement moins explicite: lorsque vous renvoyez une valeur, vous quittez automatiquement l'étendue de la fonction dans laquelle vous vous trouvez et vous retournez à l'appelant. Ainsi, tout code ci-après ne s'exécutera que si l'instruction IF n'est pas évaluée à true. et par la suite retourner quoi que ce soit.

0
Aaronontheweb

Je plaiderais pour la lisibilité. Si vous analysez des écrans de code pour essayer de comprendre ce qu'il fait, il s'agit d'une invite visuelle à l'intention du développeur.

... mais ce n'est pas vraiment nécessaire car nous commentons si bien notre code, n'est-ce pas? :)

0
SteveCav

À mon avis, le second a plus de sens. C'est plutôt une action «par défaut», comme un commutateur. Si cela ne correspond à aucun des autres points de sortie, faites-le. Vous n'avez pas vraiment besoin d'un autre là-bas. Je dirais que si la fonction entière est seulement si et sinon, alors une autre aurait du sens là-dedans parce que c'est un conditionnel géant. Si plusieurs conditions et autres fonctions y sont exécutées, un retour par défaut à la fin sera utilisé.

0
animuson

Bien qu'avoir une autre est correct et qu'il n'y a rien de mal en termes de logique et de facilité d'exécution, j'aime éviter le moment WTF initial lorsque la fonction n'a aucune instruction de retour en dehors de la portée de if/else.

0
Anthony

Comme vous pouvez le constater, différentes personnes ont des opinions différentes sur la lisibilité. Certaines personnes pensent que moins de lignes de code ont tendance à rendre le code plus lisible. D'autres pensent que la symétrie de la seconde forme la rend plus lisible.

Mon point de vue est probablement que les deux points de vue sont corrects ... pour les personnes qui les détiennent. Et le corollaire est que vous ne pouvez pas écrire du code que tout le monde trouve lisible de manière optimale. Donc, le meilleur conseil est de suivre ce que votre norme de codage mandatée dit de faire (si elle dit quoi que ce soit à ce sujet) et utilisez généralement votre bon sens. (Si vous êtes accablé par un insolent criard qui insiste sur le fait que son chemin est "juste" ... suivez le courant.)

0
Stephen C

Parce que c'est la même chose que d'écrire l'un des éléments suivants qui apporte la preuve de l'intention du programmeur:

boolean containsSmiley(String s) {
    if (s == null)   // The curly braces are not even necessary as the if contains only one instruction.
        return false;

    return s.contains(":)");
}

Ou même ceci:

boolean constainsSMiley(String s) {
    return string.IsNullOrEmpty(s) ? false : s.Contains(":)");
}

Ces deux formes sont:

  1. Plus élégant;
  2. Plus facile à lire;
  3. Plus maigre et rapide pour le programmeur de lecture.
0
Will Marcouiller

Eh bien, une partie de la raison est juste de convention, mais il y a un avantage à la forme ci-dessus ...

Il est typique lors du codage d'une instruction return de faire de la dernière instruction votre valeur de retour par défaut. Cela facilite principalement la refactorisation - sinon, les clauses ont tendance à se retrouver dans d'autres structures, ou pourraient être accidentellement déplacées plus profondément dans l'arbre.

0
jayshao