186 votes

Pourquoi lancer explicitement une NullPointerException plutôt que de le laisser se produire naturellement?

Lors de la lecture du code source de JDK, je trouve commun que l’auteur vérifie les paramètres s’ils sont nuls, puis lance manuellement la nouvelle NullPointerException (). Pourquoi font-ils cela? Je pense qu'il n'est pas nécessaire de le faire car il lancera une nouvelle NullPointerException () lorsqu'il appellera une méthode. (Voici un code source de HashMap, par exemple :)

 public V computeIfPresent(K key,
                          BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
    if (remappingFunction == null)
        throw new NullPointerException();
    Node<K,V> e; V oldValue;
    int hash = hash(key);
    if ((e = getNode(hash, key)) != null &&
        (oldValue = e.value) != null) {
        V v = remappingFunction.apply(key, oldValue);
        if (v != null) {
            e.value = v;
            afterNodeAccess(e);
            return v;
        }
        else
            removeNode(hash, key, null, false, true);
    }
    return null;
}
 

261voto

shmosel Points 4840

Il y a un certain nombre de raisons qui viennent à l'esprit, plusieurs sont étroitement liées:

Fail-fast: Si c'est voué à l'échec, mieux à l'échec, et plutôt tôt que tard. Cela permet des problèmes à être pris plus près de leur source, les rendant plus faciles à identifier et récupérer. Il permet aussi d'éviter de gaspiller des cycles de PROCESSEUR sur le code qui est lié à l'échec.

Objectif: Jeter l'exception explicitement fait clairement savoir aux responsables que l'erreur est là à dessein et l'auteur est au courant des conséquences.

La cohérence: Si l'erreur ont été autorisés à se produire naturellement, il pourrait ne pas se produire dans tous les scénarios. Si aucune correspondance n'est trouvée, par exemple, remappingFunction ne serait jamais utilisée et l'exception ne serait pas levée. La validation d'une entrée à l'avance permet plus déterministe du comportement et plus claire de la documentation.

Stabilité: Code évolue au fil du temps. Code qui rencontre une exception naturellement pourrait, après un peu de refactoring, cesser de le faire, ou le faire dans des circonstances différentes. Jeter explicitement, il est moins probable pour le comportement à modifier par inadvertance.

40voto

David Conrad Points 3529

C'est pour des raisons de clarté, la cohérence, et pour empêcher les autres, le travail inutile d'être exécuté.

Demander ce qui se passerait s'il n'y avait pas un garde de la clause au sommet de la méthode. Il serait toujours appeler hash(key) et getNode(hash, key) même lorsqu' null avait été adoptée dans le de la remappingFunction avant le NPE a été levée.

Pire encore, si l' if condition est - false puis nous prenons l' else de la branche, qui n'utilise pas le remappingFunction , ce qui signifie que la méthode n'est pas toujours jeter NPE lorsqu'un null est passé; s'il ne dépend de l'état de la carte.

Les deux scénarios sont mauvais. Si null n'est pas une valeur valide pour remappingFunction la méthode doit toujours jeter une exception, indépendamment de l'état interne de l'objet au moment de l'appel, et il doit le faire sans faire des travaux inutiles que est inutile étant donné qu'il va lancer. Enfin, c'est un bon principe de nettoyer, effacer le code pour avoir le droit de garde à l'avant, de sorte que si l'on examine le code source peut facilement voir qu'il va le faire.

Même si l'exception était actuellement jetés par chaque branche de code, il est possible qu'une future révision du code changer cela. Effectuer la vérification au début assure il va certainement être effectuée.

25voto

Stephen C Points 255558

En outre, pour les raisons énumérées par @shmosel excellente réponse ...

Performance: Il peut y avoir / ont été les avantages de performance (sur certaines machines virtuelles) pour lancer le NPE explicitement plutôt que de laisser la machine faire.

Cela dépend de la stratégie de l'interprète de Java et compilateur JIT prendre à détecter le déréférencement de pointeurs null. Une stratégie est de ne pas tester la valeur null, mais au lieu de piéger le SIGSEGV qui se produit lorsqu'une instruction essaie d'accéder à l'adresse 0. C'est l'approche plus rapide dans le cas où la référence est toujours valide, mais il est cher dans le NPE cas.

Un test explicite pour null dans le code de façon à éviter les SIGSEGV de performances dans un scénario où les Npe sont fréquentes.

(Je doute que ce serait un bon micro-optimisation moderne dans une JVM, mais il aurait pu être dans le passé.)


Compatibilité: probablement La raison qu'il n'y a pas de message dans la seule exception est pour la compatibilité avec les Npe sont générées par la JVM elle-même. Dans une implémentation compatible Java, un NPE jeté par la JVM a un null message. (Android Java est différent.)

20voto

EJoshuaS Points 7022

En dehors de ce que d'autres personnes l'ont souligné, il est intéressant de noter le rôle de la convention ici. En C#, par exemple, vous avez également la même convention explicitement lever une exception, dans des cas comme cela, mais c'est plus précisément un ArgumentNullException, ce qui est un peu plus spécifiques. (Le C# convention est qu' NullReferenceException toujours représente un bug de quelque nature: tout simplement, il ne faut pas toujours se produire dans le code de production; accordé, ArgumentNullException le fait habituellement, trop, mais il pourrait être un bug de plus le long de la ligne de "tu ne comprends pas comment utiliser la bibliothèque correctement" genre de bug).

Donc, en gros, en C#, NullReferenceException signifie que votre programme a essayé de l'utiliser, alors qu' ArgumentNullException , cela signifie qu'il a reconnu que la valeur a été mal et il n'a même pas pris la peine d'essayer de l'utiliser. Les conséquences peuvent en fait être différents (selon les circonstances), car ArgumentNullException signifie que la méthode en question n'ont pas d'effets secondaires pour l'instant (car elle n'est pas la méthode de conditions préalables).

D'ailleurs, si vous êtes à la collecte de quelque chose comme ArgumentNullException ou IllegalArgumentException, c'est en partie le point de faire le chèque: vous souhaitez une autre exception que vous feriez "normalement" obtenir.

De toute façon, déclenchant explicitement l'exception renforce les bonnes pratiques pour être plus explicite à propos de votre méthode de pré-conditions et les arguments, ce qui rend le code plus facile à lire, utiliser et entretenir. Si vous n'avez pas explicitement vérifiez null, je ne sais pas si c'est parce que tu pensais que personne ne serait jamais passer un null argument, vous êtes à compter de jeter l'exception de toute façon, ou vous avez simplement oublié de vérifier que.

12voto

EJP Points 113412

C'est ainsi que vous obtiendrez l'exception dès que vous aurez commis l'erreur, plutôt que plus tard, lorsque vous utiliserez la carte, sans comprendre pourquoi.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X