Solution True-way en Java: parsing 2 nombres à partir de 2 chaînes puis retourne leur sum

Assez une question stupide. Vu le code:

public static int sum(Ssortingng a, Ssortingng b) /* throws? WHAT? */ { int x = Integer.parseInt(a); // throws NumberFormatException int y = Integer.parseInt(b); // throws NumberFormatException return x + y; } 

Pourriez-vous dire si c’est bien Java ou non? Ce dont je parle, c’est que NumberFormatException est une exception non NumberFormatException . Vous n’avez pas à le spécifier dans la signature sum() . De plus, pour autant que je sache, l’idée d’exceptions non contrôlées est juste pour signaler que l’implémentation du programme est incorrecte, et plus encore, intercepter des exceptions non vérifiées est une mauvaise idée, car c’est comme réparer un programme incorrect à l’exécution .

Quelqu’un voudrait-il préciser si:

  1. Je devrais spécifier NumberFormatException dans le cadre de la signature de la méthode.
  2. Je devrais définir ma propre exception vérifiée ( BadDataException ), gérer NumberFormatException dans la méthode et la relancer en tant que BadDataException .
  3. Je devrais définir ma propre exception vérifiée ( BadDataException ), valider les deux chaînes comme des expressions régulières et lancer mon BadDataException si elle ne correspond pas.
  4. Ton idée?

Mise à jour :

Imaginez, ce n’est pas un framework open-source, que vous devriez utiliser pour une raison quelconque. Vous regardez la signature de la méthode et pensez – “OK, ça ne jette jamais”. Puis, un jour, vous avez une exception. Est-ce normal?

Mise à jour 2 :

Certains commentaires disent que ma sum(Ssortingng, Ssortingng) est une mauvaise conception. Je suis tout à fait d’accord, mais pour ceux qui pensent que le problème initial ne se poserait jamais si nous avions un bon design, voici une question supplémentaire:

La définition du problème est la suivante: vous avez une source de données où les nombres sont stockés sous forme de Ssortingng . Cette source peut être un fichier XML, une page Web, une fenêtre de bureau avec 2 zones d’édition, etc.

Votre objective est d’implémenter la logique qui prend ces 2 Ssortingng s, les convertit en int s et affiche la boîte de message indiquant “la sum est xxx”.

Quelle que soit l’approche que vous utilisez pour concevoir / implémenter ceci, vous aurez ces 2 points de fonctionnalité interne :

  1. Un endroit où vous convertissez Ssortingng en int
  2. Un endroit où vous ajoutez 2 int s

La principale question de mon post d’origine est la suivante:

Integer.parseInt() s’attend à ce que la chaîne correcte soit transmise. Chaque fois que vous passez une mauvaise chaîne , cela signifie que votre programme est incorrect (pas ” votre utilisateur est un idiot”). Vous devez implémenter le morceau de code où, d’une part, vous avez Integer.parseInt () avec la sémantique MUST et d’autre part, vous devez être d’accord avec les cas où la saisie est incorrecte.

Donc, brièvement: comment implémenter la sémantique de SHOULD si je n’ai que des bibliothèques MUST .

C’est une bonne question. Je souhaite que plus de gens pensent à de telles choses.

IMHO, jetant des exceptions non vérifiées est acceptable si vous avez passé des parameters d’ordures.

En règle générale, vous ne devriez pas lancer BadDataException car vous ne devriez pas utiliser les exceptions pour contrôler le stream de programmes. Les exceptions sont pour l’exceptionnel. Les appelants de votre méthode peuvent savoir avant d’ appeler si leurs chaînes sont des nombres ou non, ainsi, il est possible d’éviter de transmettre des ordures et peut donc être considéré comme une erreur de programmation , ce qui signifie que des exceptions non vérifiées sont acceptables.

En ce qui concerne la déclaration throws NumberFormatException – ce n’est pas très utile, car peu de personnes remarqueront que NumberFormatException n’est pas cochée. Cependant, les IDE peuvent s’en servir et proposer de les emballer correctement. Une bonne option consiste à utiliser également javadoc, par exemple:

 /** * Adds two ssortingng numbers * @param a * @param b * @return * @throws NumberFormatException if either of a or b is not an integer */ public static int sum(Ssortingng a, Ssortingng b) throws NumberFormatException { int x = Integer.parseInt(a); int y = Integer.parseInt(b); return x + y; } 

EDITED :
Les commentateurs ont fait des remarques valables. Vous devez examiner comment cela sera utilisé et la conception globale de votre application.

Si la méthode est utilisée partout, et qu’il est important que tous les appelants gèrent les problèmes, déclarez la méthode en lançant une exception vérifiée (forçant les appelants à gérer les problèmes), mais en encombrant le code avec try/catch blocs try/catch .

Si, par contre, nous utilisons cette méthode avec des données auxquelles nous faisons confiance, alors déclarez-la comme ci-dessus, car elle ne devrait jamais exploser et vous éviterez l’encombrement de code de blocs d’ try/catch essentiellement inutiles.

A mon avis, il serait préférable de gérer la logique des exceptions aussi loin que possible. Je préférerais donc la signature

  public static int sum(int a, int b); 

Avec votre signature de méthode, je ne changerais rien. Soit vous êtes

  • En utilisant des valeurs incorrectes par programme, vous pouvez au contraire valider votre algorithme de producteur
  • ou envoi de valeurs, par exemple, une entrée utilisateur, auquel cas ce module doit effectuer la validation

Par conséquent, la gestion des exceptions dans ce cas devient un problème de documentation .

Number 4. Comme indiqué, cette méthode ne doit pas prendre des chaînes comme parameters à prendre en compte. Dans ce cas (depuis que java enveloppe au lieu de déborder) il n’y a aucune possibilité d’exception.

  x = sum(Integer.parseInt(a), Integer.parseInt(b)) 

est beaucoup plus clair quant à ce que l’on veut dire que x = sum(a, b)

Vous voulez que l’exception se produise le plus près possible de la source (entrée).

En ce qui concerne les options 1 à 3, vous ne définissez pas d’exception, car vos appelants supposent que votre code ne peut pas échouer. Vous définissez une exception pour définir ce qui se produit dans des conditions de défaillance connues. C’est-à-dire si vous avez une méthode qui est un wrapper autour d’un autre object et qu’elle lance une exception, transmettez-la. Ce n’est que si l’exception est propre à votre méthode que vous devez lancer une exception personnalisée (frex, dans votre exemple, si sum était censé renvoyer uniquement des résultats positifs, vérifier cela et lancer une exception serait approprié si java jetez une exception de débordement au lieu de l’emballer, vous transmetsortingez cela, ne le définiriez pas dans votre signature, ne le renommeriez pas ou ne le mangeriez pas.

Mise à jour en réponse à la mise à jour de la question:

Donc, brièvement: comment implémenter la sémantique de SHOULD si je n’ai que des bibliothèques MUST.

La solution consiste à envelopper la bibliothèque MUST et à renvoyer une valeur SHOULD. Dans ce cas, une fonction qui renvoie un entier. Ecrivez une fonction qui prend une chaîne et retourne un object Integer – soit il fonctionne, soit il retourne null (comme Ints.tryParse de goyave). Si votre validation est distincte de votre opération, votre opération devrait prendre en compte. Le fait que votre opération soit appelée avec des valeurs par défaut lorsque vous avez des données invalides ou que vous faites autre chose dépendra de vos spécifications – tout ce que je peux dire, c’est qu’il est peu probable que la décision soit prise méthode.

1. Je devrais spécifier NumberFormatException dans le cadre de la signature de la méthode.

Je le pense. C’est une belle documentation.

2. Je devrais définir ma propre exception vérifiée (BadDataException), gérer NumberFormatException dans la méthode et la relancer en tant que BadDataException.

Parfois oui. Les exceptions vérifiées sont considérées comme meilleures dans certains cas, mais leur utilisation est une PITA. C’est pourquoi de nombreux frameworks (par exemple, Hibernate) utilisent uniquement des exceptions d’exécution.

3. Je devrais définir ma propre exception vérifiée (BadDataException), valider les deux chaînes comme des expressions régulières et lancer mon exception BadDataException si elle ne correspond pas.

Jamais. Plus de travail, moins de vitesse (à moins que vous ne vous attendiez à ce que l’exception soit une règle) et aucun gain.

4. Votre idée?

Pas du tout.

N ° 4

Je pense que je ne changerais pas du tout la méthode. Je mettrais un test autour de la méthode d’appel ou une version supérieure dans la stack-trace où je me trouve dans un contexte où je peux récupérer avec une logique d’entreprise à partir de l’exception.

Je ne serais pas sûr de faire le n ° 3 comme je le juge exagéré.

En supposant que ce que vous écrivez va être consommé (comme une API) par quelqu’un d’autre, alors vous devriez aller avec 1, NumberFormatException est spécifiquement destiné à communiquer de telles exceptions et devrait être utilisé.

  1. Tout d’abord, vous devez vous demander si l’utilisateur de ma méthode a besoin de vous soucier de la saisie de données erronées, ou est-il censé saisir des données correctes (dans ce cas, Ssortingng). Cette attente est également connue sous le nom de conception par contrat .

  2. et 3. Oui, vous devriez probablement définir BadDataException ou même mieux utiliser certaines des excisions comme NumberFormatException, mais plutôt laisser le message standard à afficher. Attrapez NumberFormatException dans la méthode et relancez-le avec votre message, sans oublier d’inclure la trace de la stack d’origine.

  3. Cela dépend de la situation. Je vais probablement relancer NumberFormatException avec des informations supplémentaires. Et il doit également y avoir une explication javadoc de ce que sont les valeurs attendues pour Ssortingng a, Ssortingng b

Cela dépend beaucoup du scénario dans lequel vous vous trouvez.

Cas 1. C’est toujours vous qui déboguez le code et personne d’autre et l’exception ne causera pas une mauvaise expérience utilisateur

Lancez l’exception NumberFormatException par défaut

Cas 2: Le code doit être extrêmement maintenable et compréhensible

Définissez votre propre exception et ajoutez beaucoup plus de données pour le débogage lors du lancement.

Vous n’avez pas besoin de vérifications de regex car, de toute façon, cela ira à l’exception sur les mauvaises entrées.

Si c’était un code de niveau de production, mon idée serait de définir plusieurs exceptions personnalisées, comme

  1. Exception de format numérique
  2. Exception de dépassement de capacité
  3. Exception nulle etc …

et faire face à toutes ces choses séparément

  1. Vous pouvez le faire pour indiquer clairement que cela peut se produire pour une saisie incorrecte. Cela peut aider quelqu’un qui utilise votre code à se souvenir de la gestion de cette situation. Plus précisément, vous indiquez clairement que vous ne le gérez pas vous-même dans le code ou que vous ne retournez pas de valeur spécifique. Bien sûr, le JavaDoc devrait également le rendre clair.
  2. Seulement si vous voulez forcer l’appelant à gérer une exception vérifiée.
  3. Cela semble exagéré. Faites confiance à l’parsing pour détecter les mauvaises entrées.

De manière générale, une exception NumberFormaException est décochée car il est prévu que les entrées correctement analysables sont fournies. La validation des entrées est quelque chose que vous devez gérer. Cependant, l’parsing de l’entrée est la manière la plus simple de procéder. Vous pouvez simplement laisser votre méthode en l’état et avertir dans la documentation que les entrées correctes sont attendues et que toute personne appelant votre fonction doit valider les deux entrées avant de l’utiliser.

Tout comportement exceptionnel doit être précisé dans la documentation. Soit cela doit indiquer que cette méthode retourne une valeur spéciale en cas d’échec (comme null , en changeant le type de retour en Integer ) ou la casse 1 doit être utilisée. Le faire expliciter dans la signature de la méthode permet à l’utilisateur de l’ignorer s’il assure des chaînes correctes par d’autres moyens, mais il est toujours évident que la méthode ne gère pas elle-même ce type de défaillance.

Répondez à votre question mise à jour.

Oui, il est parfaitement normal d’obtenir des exceptions “sursockets”. Pensez à toutes les erreurs d’exécution que vous avez rencontrées lors de la programmation.

 eg ArrayIndexOutofBound 

Aussi une exception de surprise commune à chaque boucle.

 ConcurrentModificationException or something like that 

Bien que je sois d’accord avec la réponse voulant que l’exception d’exécution soit autorisée à être percée, du sharepoint vue de la conception et de la convivialité, il serait judicieux de l’incorporer dans une exception IllegalArgumentException plutôt que de la lancer comme NumberFormatException. Cela rend alors le contrat de votre méthode plus clair, par lequel il déclare qu’un argument illégal lui a été transmis à cause duquel il a émis une exception.

En ce qui concerne la mise à jour de la question “Imaginez, ce n’est pas un framework open-source, vous devriez l’utiliser pour une raison quelconque. Vous regardez la signature de la méthode et vous pensez” OK, elle ne lève jamais “. . Est-ce normal?” Le javadoc de votre méthode doit toujours définir le comportement de votre méthode (pré et post contraintes). Pensez aux lignes des interfaces de la collection say où, si un null n’est pas autorisé, le javadoc indique qu’une exception de pointeur nul sera levée bien qu’il ne fasse jamais partie de la signature de la méthode.

Comme vous parlez de bonnes pratiques java, à mon avis, il est toujours préférable

  • Pour gérer l’exception non vérifiée, parsingz-la et utilisez une exception personnalisée non contrôlée.

  • De même, en lançant une exception non contrôlée personnalisée, vous pouvez append le message Exception que votre client peut comprendre et imprimer la trace de la stack de l’exception d’origine.

  • Il n’est pas nécessaire de déclarer une exception personnalisée comme “jette” car elle n’est pas cochée.

  • De cette façon, vous ne violez pas l’utilisation des exceptions non contrôlées pour lesquelles le client du code comprend facilement la raison et la solution de l’exception.

  • La documentation correcte dans java-doc est également une bonne pratique et aide beaucoup.

Je pense que cela dépend de votre objective, mais je le documenterais au minimum:

 /** * @return the sum (as an int) of the two ssortingngs * @throws NumberFormatException if either ssortingng can't be converted to an Integer */ public static int sum(Ssortingng a, Ssortingng b) int x = Integer.parseInt(a); int y = Integer.parseInt(b); return x + y; } 

Ou, prenez une page du code source Java pour la classe java.lang.Integer:

 public static int parseInt(java.lang.Ssortingng ssortingng) throws java.lang.NumberFormatException; 

Qu’en est-il du modèle de validation des entrées implémenté par la bibliothèque ‘Guava’ de Google ou la bibliothèque ‘Validator’ d’Apache ( comparaison )?

D’après mon expérience, il est considéré comme une bonne pratique de valider les parameters d’une fonction au début de la fonction et de lancer des exceptions le cas échéant.

Je considère également que cette question est largement indépendante de la langue. La «bonne pratique» ici s’appliquerait à toutes les langues qui ont des fonctions pouvant prendre des parameters qui peuvent ou non être valides.

Je pense que votre toute première phrase de “question assez stupide” est très pertinente. Pourquoi voudriez-vous écrire une méthode avec cette signature en premier lieu? Est-il même logique de faire la sum de deux chaînes? Si la méthode appelante veut faire la sum de deux chaînes, il incombe à la méthode appelante de s’assurer qu’elles sont valides et de les convertir avant d’appeler la méthode.

Dans cet exemple, si la méthode appelante ne peut pas convertir les deux chaînes en un int, cela peut faire plusieurs choses. Cela dépend vraiment de la couche à laquelle cette sommation se produit. Je suppose que la conversion de chaîne sera très proche du code frontal (si cela a été fait correctement), de sorte que le cas 1. serait le plus probable:

  1. Définir un message d’erreur et arrêter le traitement ou redirect vers une page d’erreur
  2. Renvoyer false (c.-à-d. Que la sum serait placée dans un autre object et ne serait pas obligée de la retourner)
  3. Jetez quelques BadDataException comme vous le suggérez, mais à moins que la sum de ces deux nombres ne soit très importante, cela est excessif, et comme mentionné ci-dessus, cela est probablement une mauvaise conception car cela implique que la conversion est faite au mauvais endroit

Il y a beaucoup de réponses intéressantes à cette question. Mais je veux encore append ceci:

Pour l’parsing de chaîne, je préfère toujours utiliser des “expressions régulières”. Le package java.util.regex est là pour nous aider. Je vais donc finir avec quelque chose comme ça, qui ne jette aucune exception. C’est à moi de retourner une valeur spéciale si je veux attraper une erreur:

 import java.util.regex.Pattern; import java.util.regex.Matcher; public static int sum(Ssortingng a, Ssortingng b) { final Ssortingng REGEX = "\\d"; // a single digit Pattern pattern = Pattern.comstack(REGEX); Matcher matcher = pattern.matcher(a); if (matcher.find()) { x = Integer.matcher.group(); } Matcher matcher = pattern.matcher(b); if (matcher.find()) { y = Integer.matcher.group(); } return x + y; } 

Comme on peut le voir, le code est juste un peu plus long, mais nous pouvons gérer ce que nous voulons (et définir des valeurs par défaut pour x et y, contrôler ce qui se passe avec les clauses else, etc.). routine, à laquelle on peut passer des chaînes, des valeurs de retour par défaut, du code REGEX à comstackr, des messages d’erreur à jeter, …

J’espère que c’était utile.

Attention: je n’ai pas pu tester ce code, veuillez donc excuser d’éventuels problèmes de syntaxe.

Vous êtes confronté à ce problème car vous laissez les erreurs utilisateur se propager trop profondément au cœur de l’application et en partie aussi parce que vous abusez des types de données Java.

Vous devez avoir une séparation plus nette entre la validation des entrées utilisateur et la logique métier, utiliser un typage de données correct, et ce problème disparaîtra de lui-même.

Le fait est que la sémantique d’ Integer.parseInt() est connue – son but premier est d’parsingr les entiers valides . Vous manquez une étape explicite de validation / parsing des entrées utilisateur.