Lancez-vous une argumentexception ou argumentnullexception à partir de méthodes privées?

20

Je revoyais juste du code que j'avais écrit il y a quelque temps, et je peux voir que j'ai quelques méthodes privées qui lancent des exceptions de argument et / ou des exceptions d'argument s'il y a des problèmes avec les paramètres des méthodes.

Je suppose que ma justification est que cela aide à pérenniser l'application si quelqu'un essaie de "mal" utiliser la méthode à l'avenir. Cependant, étant donné qu'il s'agit d'une méthode privée et que les personnes susceptibles d'appeler cette méthode peuvent voir les commentaires et le code associés, il est tout simplement inutile de lancer cela. Cela ne fait certainement pas de mal de les avoir, bien que cela ajoute de l'encombrement.

Mon sentiment est que ces exceptions sont généralement plus utiles sur quelque chose comme une API qui va être exposée publiquement.

Mr Moose
la source

Réponses:

22

Normalement, pour les méthodes privées, vous ne lancez pas d'exceptions car, comme vous l'avez écrit, le développeur est censé savoir comment et d'où il appelle la méthode. En tant que tel, les variables transmises en tant que paramètres à la méthode privée doivent être vérifiées en dehors de la méthode, c'est-à-dire avant de l'appeler. Lancer "InvalidArgumentException" et d'autres exceptions de ce type est considéré comme une bonne pratique pour les méthodes publiques (que vous écriviez une "API" ou non).

Pour les cas où vous souhaitez lever "InvalidArgumentException", il convient de mentionner qu'il existe une Assertclasse dans l'API Spring pour Java depuis la version 1.1.2. Il m'a été très utile - du moins pour moi - d'écrire moins de code pour effectuer des vérifications.

Vous pouvez cependant utiliser des "assertions" pour vérifier les paramètres dans les méthodes privées. C'est l'un de leurs véritables objectifs. Ce sont plus de raisons de les utiliser, consultez le lien suivant qui explique également en détail quand utiliser les assertions et quand utiliser les exceptions. Les assertions ne doivent pas être incluses dans le code de production et le compilateur les supprime par défaut. C'est donc ce que vous cherchez: aider les développeurs, invisible pour les utilisateurs. En Java, vous devez utiliser un indicateur spécial ("-ea") pour indiquer au compilateur d'activer les assertions. Vous pouvez les considérer comme des amis de "débogage".

Voici comment utiliser les assertions dans:

Jalayn
la source
1
Apache Commons a également une classe Validate qui fonctionne de manière similaire à la classe Assert de Spring
Rosa Richter
@cantido yes et j'ajouterais également que la classe Preconditions dans Google's Guava fonctionne de la même manière. Merci pour l'information :-)
Jalayn
2

Comme tout le reste, cela dépend ....

Si les méthodes publiques sont de simples wrappers qui appellent la méthode privée (dans le sens d'une méthode privée surchargée), il peut être judicieux de lever une exception dans la méthode privée au lieu d'enregistrer chaque méthode publique.

Généralement, s'il ne répond pas à la définition ci-dessus, je ne vérifierais généralement pas les arguments / levons une exception sur une méthode privée. Bien qu'il existe d'autres cas, je le fais généralement dans une méthode privée avant d'effectuer une opération coûteuse qui pourrait échouer à mi-chemin si les arguments n'étaient pas valides.

Ken Henderson
la source
2

Je me rends compte que même si la question n'a pas de balise de langue, il s'agit probablement implicitement de «langues du café». Mais juste pour être complet, je voudrais mentionner le consensus apparent quelque peu divergent dans le monde C ++.

Les programmeurs C ++ sont généralement intéressés par trois choses:

  • Aura-t-il zéro frais généraux dans les versions optimisées? (Autrement dit, peut-il être «compilé»?)
  • Puis-je l'utiliser pour intercepter un débogueur juste au point où l'erreur a été détectée?
  • Puis-je l'utiliser pour signaler des problèmes à partir des fonctions déclarées noexcept?

Dans le passé, j'ai abordé le premier problème en écrivant du code comme celui-ci

int
factorial(const int n)
{
  if (CHECK_ARGS)
    {
      if (n < 0)
        throw std::invalid_argument {"n < 0"};
    }
  int fac = 1;
  for (int i = 2; i <= n; ++i)
    fac *= i;
  return fac;
}

CHECK_ARGSest #defined à une constante de temps de compilation afin que le compilateur puisse éliminer complètement tout le code de vérification des arguments dans les builds optimisées. (Je ne dis pas que la compilation des vérifications est une bonne chose en général, mais je crois qu'un utilisateur devrait avoir la possibilité de les compiler.)

J'aime toujours dans cette solution que l'argument vérifiant le code soit clairement visible, regroupé dans le if. Cependant, les deuxième et troisième problèmes ne sont pas résolus par cela. Par conséquent, je penche maintenant davantage vers l'utilisation d'une assertmacro pour la vérification des arguments.

Les normes de codage Boost sont d'accord avec ceci:

Qu'en est-il des erreurs du programmeur?

En tant que développeur, si j'ai violé une condition préalable d'une bibliothèque que j'utilise, je ne veux pas que la pile se déroule. Ce que je veux, c'est un vidage de mémoire ou l'équivalent - un moyen d'inspecter l'état du programme au point exact où le problème a été détecté. Cela signifie généralement assert()ou quelque chose comme ça.

Il y a eu une conférence très intéressante donnée par John Lakos à CppCon'14 intitulée Programmation défensive bien faite ( partie 1 , partie 2 ). Dans la première partie de son intervention, il aborde la théorie des contrats et des comportements indéfinis. Dans la deuxième partie, il présente ce que je considère comme une très bonne proposition de vérification systématique des arguments. En substance, il propose des macros d'assertion qui permettent à l'utilisateur de sélectionner la part du budget (en termes d'utilisation du processeur) qu'il est prêt à donner à la bibliothèque pour la vérification des arguments et à la bibliothèque d'utiliser judicieusement ce budget. En outre, l'utilisateur peut également installer une fonction globale de gestion des erreurs qui sera appelée en cas de détection d'un contrat rompu.

En ce qui concerne l'aspect qu'une fonction est privée, je ne pense pas que cela signifie que nous ne devrions jamais la faire vérifier ses arguments. Nous pouvons faire davantage confiance à notre propre code pour ne pas violer le contrat d'une fonction interne, mais nous savons également que nous ne sommes pas parfaits non plus. La vérification des arguments dans les fonctions internes est tout aussi utile pour détecter nos propres bogues que pour les fonctions publiques pour détecter les bogues dans le code client.

5gon12eder
la source
1

Considérez la structure suivante:

  1. Logique interne: cette fonction suppose d'être appelée avec des paramètres corrects et utilise donc des assertions pour vérifier les préconditions, les postconditions et les invariants pour vérifier votre logique interne.

  2. Wrapper Interface utilisateur: Cette fonction enveloppe la fonction interne et utilise InvalidArgumentExceptions pour gérer de mauvaises valeurs et de dire à l'utilisateur de corriger ses entrées: Assert(x).hasLength(4);, Assume(y).isAlphanumeric();, Assert(z).isZipCode();, Assume(mailAdress).matchesRegex(regex_MailAdress);, Reject(x).ifEmpty();, etc.

  3. Encapsuleur d'interface par lots: cette fonction encapsule la fonction interne et utilise la journalisation, les marquages ​​de validité et les statistiques pour gérer les valeurs incorrectes sans interrompre une tâche de longue durée. Les marquages ​​pourraient être utilisés ultérieurement par une personne vérifiant et nettoyant la base de données de résultats.

  4. Encapsuleur d'interface de ligne de commande: cette fonction enveloppe la fonction interne et demande à nouveau la dernière entrée.

Vous devez utiliser les deux - assertions et exceptions - dans différentes méthodes pour différentes tâches. Vous devez séparer la logique interne de la vérification des paramètres. Comparez-le à la séparation du modèle, de la vue et du contrôleur.

Ralf K.
la source
0

Il existe de meilleures façons d'éviter la vérification des références nulles: utilisez un contrat de code ou un cadre AOP pour effectuer la vérification pour vous. Google "contrat de code c #" ou "postsharp".

Codisme
la source
Je suppose que ma question s'étendrait également aux contrats de code. Est-il nécessaire de vérifier les conditions préalables de la méthode dans une méthode privée (c.-à-d. Pour l'épreuvage futur ou pour vous empêcher de vous tirer une balle dans le pied)?
M. Moose