Bon moyen d’encapsuler Integer.parseInt ()

J’ai un projet dans lequel nous utilisons souvent Integer.parseInt() pour convertir un Ssortingng en int. Lorsque quelque chose ne va pas (par exemple, la Ssortingng n’est pas un nombre, mais la lettre a ou autre), cette méthode lancera une exception. Cependant, si je dois gérer des exceptions dans mon code partout, cela commence à paraître très moche très rapidement. Je voudrais mettre cela dans une méthode, cependant, je ne sais pas comment retourner une valeur propre afin de montrer que la conversion a mal tourné.

En C ++, j’aurais pu créer une méthode qui accepte un pointeur sur un int et laisser la méthode elle-même renvoyer true ou false. Cependant, pour autant que je sache, ce n’est pas possible en Java. Je pourrais aussi créer un object contenant une variable true / false et la valeur convertie, mais cela ne semble pas idéal non plus. La même chose vaut pour une valeur globale, et cela pourrait me causer des problèmes avec le multithreading.

Alors, y a-t-il une façon propre de le faire?

Vous pouvez retourner un Integer place d’un int , en renvoyant null en cas d’échec d’parsing.

Dommage que Java ne fournisse pas de moyen de le faire sans qu’il y ait une exception renvoyée en interne – vous pouvez masquer l’exception (en l’attrapant et en renvoyant null), mais cela pourrait toujours poser problème si vous parsingz des centaines de milliers de bits de données fournies par l’utilisateur.

EDIT: Code pour une telle méthode:

 public static Integer tryParse(Ssortingng text) { try { return Integer.parseInt(text); } catch (NumberFormatException e) { return null; } } 

Notez que je ne suis pas sûr de ce que cela va faire si le text est nul. Vous devriez considérer cela – si cela représente un bogue (c.-à-d. Que votre code peut bien passer une valeur non valide, mais ne devrait jamais passer null), alors lancer une exception est approprié; Si cela ne représente pas un bogue, vous devriez probablement retourner null comme vous le feriez pour toute autre valeur non valide.

A l’origine, cette réponse utilisait le new Integer(Ssortingng) ; il utilise maintenant Integer.parseInt et une opération de boxe; De cette manière, les petites valeurs seront placées dans des objects Integer mis en cache, ce qui le rendra plus efficace dans ces situations.

Quel comportement attendez-vous quand ce n’est pas un chiffre?

Si, par exemple, vous avez souvent une valeur par défaut à utiliser lorsque l’entrée n’est pas un nombre, une méthode comme celle-ci peut être utile:

 public static int parseWithDefault(Ssortingng number, int defaultVal) { try { return Integer.parseInt(number); } catch (NumberFormatException e) { return defaultVal; } } 

Des méthodes similaires peuvent être écrites pour différents comportements par défaut lorsque l’entrée ne peut pas être analysée.

Dans certains cas, vous devez gérer les erreurs d’parsing en tant que situations de restauration rapide, mais dans d’autres cas, comme la configuration de l’application, je préfère gérer les entrées manquantes avec les valeurs par défaut avec Apache Commons Lang 3 NumberUtils .

 int port = NumberUtils.toInt(properties.getProperty("port"), 8080); 

Pour éviter le traitement des exceptions, utilisez une expression régulière pour vous assurer que vous avez tous les chiffres en premier:

 if(value.matches("\\d+") { Integer.parseInt(value); } 

Il y a Ints.tryParse() dans Guava . Il ne lève pas d’exception sur les chaînes non numériques, mais il lance une exception sur les chaînes null.

Après avoir lu les réponses à la question, je pense qu’il n’est pas nécessaire d’encapsuler ou d’envelopper la méthode parseInt, peut-être même pas une bonne idée.

Vous pouvez retourner ‘null’ comme Jon a suggéré, mais cela remplace plus ou moins une construction try / catch par un null-check. Il y a juste une petite différence sur le comportement si vous «oubliez» la gestion des erreurs: si vous n’acceptez pas l’exception, il n’y a pas d’affectation et la variable de gauche conserve l’ancienne valeur. Si vous ne testez pas null, vous serez probablement touché par la JVM (NPE).

La suggestion de Yawn me semble plus élégante, car je n’aime pas que le retour soit nul pour signaler des erreurs ou des états exceptionnels. Maintenant, vous devez vérifier l’égalité référentielle avec un object prédéfini, qui indique un problème. Mais, comme d’autres le font valoir, si vous «oubliez» à nouveau de vérifier et qu’une chaîne n’est pas analysable, le programme continue avec l’intégré enveloppé dans votre object «ERROR» ou «NULL».

La solution de Nikolay est encore plus orientée object et fonctionnera également avec les méthodes parseXXX d’autres classes d’encapsulation. Mais à la fin, il a simplement remplacé NumberFormatException par une exception OperationNotSupported – encore une fois, vous avez besoin d’un try / catch pour gérer les entrées non analysables.

Donc, c’est ma conclusion de ne pas encapsuler la méthode parseInt. J’encapsulerais seulement si je pouvais aussi append un traitement d’erreur (dépendant de l’application).

Peut-être que vous pouvez utiliser quelque chose comme ceci:

 public class Test { public interface Option { T get(); T getOrElse(T def); boolean hasValue(); } final static class Some implements Option { private final T value; public Some(T value) { this.value = value; } @Override public T get() { return value; } @Override public T getOrElse(T def) { return value; } @Override public boolean hasValue() { return true; } } final static class None implements Option { @Override public T get() { throw new UnsupportedOperationException(); } @Override public T getOrElse(T def) { return def; } @Override public boolean hasValue() { return false; } } public static Option parseInt(Ssortingng s) { Option result = new None(); try { Integer value = Integer.parseInt(s); result = new Some(value); } catch (NumberFormatException e) { } return result; } } 

Vous pouvez également répliquer le comportement C ++ que vous souhaitez très simplement

 public static boolean parseInt(Ssortingng str, int[] byRef) { if(byRef==null) return false; try { byRef[0] = Integer.parseInt(prop); return true; } catch (NumberFormatException ex) { return false; } } 

Vous utiliseriez la méthode comme ceci:

 int[] byRef = new int[1]; boolean result = parseInt("123",byRef); 

Après cela, la variable est vraie si tout se passe bien et byRef[0] contient la valeur analysée.

Personnellement, je m’en tiendrai à attraper l’exception.

Mon Java est un peu rouillé, mais laissez-moi voir si je peux vous orienter dans la bonne direction:

 public class Converter { public static Integer parseInt(Ssortingng str) { Integer n = null; try { n = new Integer(Integer.tryParse(str)); } catch (NumberFormatException ex) { // leave n null, the ssortingng is invalid } return n; } } 

Si votre valeur de retour est null , vous avez une mauvaise valeur. Sinon, vous avez un Integer valide.

Qu’en est-il de la méthode parseInt ?

Il est facile de copier-coller le contenu dans un nouvel utilitaire qui renvoie Integer ou Optional et remplace les lancers par les retours. Il semble qu’il n’y ait pas d’exceptions dans le code sous-jacent, mais une meilleure vérification .

En ignorant toute la gestion des exceptions, vous pouvez gagner du temps sur les entrées non valides. Et la méthode existe depuis JDK 1.0, il est donc peu probable que vous deviez en faire beaucoup pour la maintenir à jour.

Je vous suggère de considérer une méthode comme

  IntegerUtilities.isValidInteger(Ssortingng s) 

que vous implémentez ensuite comme bon vous semble. Si vous voulez que le résultat soit reporté – peut-être parce que vous utilisez Integer.parseInt () de toute façon – vous pouvez utiliser le tableau sortingck.

  IntegerUtilities.isValidInteger(Ssortingng s, int[] result) 

où vous définissez le résultat [0] sur la valeur entière trouvée dans le processus.

Ceci est un peu similaire à la solution de Nikolay:

  private static class Box { T me; public Box() {} public T get() { return me; } public void set(T fromParse) { me = fromParse; } } private interface Parser { public void setExclusion(Ssortingng regex); public boolean isExcluded(Ssortingng s); public T parse(Ssortingng s); } public static  boolean parser(Box ref, Parser p, Ssortingng toParse) { if (!p.isExcluded(toParse)) { ref.set(p.parse(toParse)); return true; } else return false; } public static void main(Ssortingng args[]) { Box a = new Box(); Parser intParser = new Parser() { Ssortingng myExclusion; public void setExclusion(Ssortingng regex) { myExclusion = regex; } public boolean isExcluded(Ssortingng s) { return s.matches(myExclusion); } public Integer parse(Ssortingng s) { return new Integer(s); } }; intParser.setExclusion("\\D+"); if (parser(a,intParser,"123")) System.out.println(a.get()); if (!parser(a,intParser,"abc")) System.out.println("didn't parse "+a.get()); } 

La méthode principale montre le code. Une autre façon d’implémenter l’interface Parser serait évidemment de simplement définir “\ D +” à partir de la construction et de ne rien faire avec les méthodes.

Vous pouvez lancer vos propres, mais il est aussi facile d’utiliser la méthode SsortingngUtils.isNumeric() commons lang. Il utilise Character.isDigit () pour parcourir chaque caractère de la chaîne.

Leur façon de gérer ce problème est récursive. Par exemple, lors de la lecture de données depuis la console:

 Java.util.Scanner keyboard = new Java.util.Scanner(System.in); public int GetMyInt(){ int ret; System.out.print("Give me an Int: "); try{ ret = Integer.parseInt(keyboard.NextLine()); } catch(Exception e){ System.out.println("\nThere was an error try again.\n"); ret = GetMyInt(); } return ret; } 

Pour éviter une exception, vous pouvez utiliser la méthode Format.parseObject de Java. Le code ci-dessous est fondamentalement une version simplifiée de la classe IntegerValidator d’Apache Common.

 public static boolean tryParse(Ssortingng s, int[] result) { NumberFormat format = NumberFormat.getIntegerInstance(); ParsePosition position = new ParsePosition(0); Object parsedValue = format.parseObject(s, position); if (position.getErrorIndex() > -1) { return false; } if (position.getIndex() < s.length()) { return false; } result[0] = ((Long) parsedValue).intValue(); return true; } 

Vous pouvez soit utiliser AtomicInteger ou int[] tableau sortingck selon vos préférences.

Voici mon test qui l'utilise -

 int[] i = new int[1]; Assert.assertTrue(IntUtils.tryParse("123", i)); Assert.assertEquals(123, i[0]); 

J’avais aussi le même problème. C’est une méthode que j’ai écrite pour demander à l’utilisateur une entrée et ne pas accepter l’entrée à moins que ce ne soit un entier. S’il vous plaît noter que je suis un débutant, donc si le code ne fonctionne pas comme prévu, blâme mon inexpérience!

 private int numberValue(Ssortingng value, boolean val) throws IOException { //prints the value passed by the code implementer System.out.println(value); //returns 0 is val is passed as false Object num = 0; while (val) { num = br.readLine(); try { Integer numVal = Integer.parseInt((Ssortingng) num); if (numVal instanceof Integer) { val = false; num = numVal; } } catch (Exception e) { System.out.println("Error. Please input a valid number :-"); } } return ((Integer) num).intValue(); } 

La réponse donnée par Jon Skeet est correcte, mais je n’aime pas rendre un object Integer null . Je trouve cela déroutant à utiliser. Depuis Java 8, il y a une meilleure option (à mon avis), en utilisant le

 public static OptionalInt tryParse(Ssortingng value) { try { return OptionalInt.of(Integer.parseInt(value)); } catch (NumberFormatException e) { return OptionalInt.empty(); } } 

Cela rend explicite que vous devez gérer le cas où aucune valeur n’est disponible. Je préférerais que ce genre de fonction soit ajouté à la bibliothèque java à l’avenir, mais je ne sais pas si cela arrivera un jour.

Ceci est une réponse à la question 8391979, “Java a-t-il un int.tryparse qui ne lève pas d’exception pour les données erronées? [Duplicate]” qui est fermé et lié à cette question.

Edit 2016 08 17: Ajout des méthodes lsortingmZeroes et appelées dans tryParse (). Sans les zéros en tête, numberSsortingng peut donner de faux résultats (voir les commentaires dans le code). Il y a maintenant aussi la méthode publique statique Ssortingng lsortingmZeroes (Ssortingng numberSsortingng) qui fonctionne pour les “nombres” positifs et négatifs (END Edit)

Vous trouverez ci-dessous une classe rudimentaire de Wrapper (boxing) pour int avec une méthode tryParse () (similaire à C #) hautement optimisée, qui parsing la chaîne elle-même et est un peu plus rapide que Integer.parseInt (Ssortingng s) de Java:

 public class IntBoxSimple { // IntBoxSimple - Rudimentary class to implement a C#-like tryParse() method for int // A full blown IntBox class implementation can be found in my Github project // Copyright (c) 2016, Peter Sulzer, Fürth // Program is published under the GNU General Public License (GPL) Version 1 or newer protected int _n; // this "boxes" the int value // BEGIN The following statements are only executed at the // first instantiation of an IntBox (ie only once) or // already comstackd into the code at comstack time: public static final int MAX_INT_LEN = Ssortingng.valueOf(Integer.MAX_VALUE).length(); public static final int MIN_INT_LEN = Ssortingng.valueOf(Integer.MIN_VALUE).length(); public static final int MAX_INT_LASTDEC = Integer.parseInt(Ssortingng.valueOf(Integer.MAX_VALUE).subssortingng(1)); public static final int MAX_INT_FIRSTDIGIT = Integer.parseInt(Ssortingng.valueOf(Integer.MAX_VALUE).subssortingng(0, 1)); public static final int MIN_INT_LASTDEC = -Integer.parseInt(Ssortingng.valueOf(Integer.MIN_VALUE).subssortingng(2)); public static final int MIN_INT_FIRSTDIGIT = Integer.parseInt(Ssortingng.valueOf(Integer.MIN_VALUE).subssortingng(1,2)); // END The following statements... // lsortingmZeroes() methods added 2016 08 16 (are required by tryParse() methods) public static Ssortingng lsortingmZeroes(Ssortingng s) { if (s.charAt(0) == '-') return lsortingmZeroesNegative(s); else return lsortingmZeroesPositive(s); } protected static Ssortingng lsortingmZeroesNegative(Ssortingng s) { int i=1; for ( ; s.charAt(i) == '0'; i++); return ("-"+s.subssortingng(i)); } protected static Ssortingng lsortingmZeroesPositive(Ssortingng s) { int i=0; for ( ; s.charAt(i) == '0'; i++); return (s.subssortingng(i)); } public static boolean tryParse(Ssortingng s,IntBoxSimple intBox) { if (intBox == null) // intBoxSimple=new IntBoxSimple(); // This doesn't work, as // intBoxSimple itself is passed by value and cannot changed // for the caller. I. e. "out"-arguments of C# cannot be simulated in Java. return false; // so we simply return false s=s.sortingm(); // leading and trailing whitespace is allowed for Ssortingng s int len=s.length(); int rslt=0, d, dfirst=0, i, j; char c=s.charAt(0); if (c == '-') { if (len > MIN_INT_LEN) { // corrected (added) 2016 08 17 s = lsortingmZeroesNegative(s); len = s.length(); } if (len >= MIN_INT_LEN) { c = s.charAt(1); if (!Character.isDigit(c)) return false; dfirst = c-'0'; if (len > MIN_INT_LEN || dfirst > MIN_INT_FIRSTDIGIT) return false; } for (i = len - 1, j = 1; i >= 2; --i, j *= 10) { c = s.charAt(i); if (!Character.isDigit(c)) return false; rslt -= (c-'0')*j; } if (len < MIN_INT_LEN) { c = s.charAt(i); if (!Character.isDigit(c)) return false; rslt -= (c-'0')*j; } else { if (dfirst >= MIN_INT_FIRSTDIGIT && rslt < MIN_INT_LASTDEC) return false; rslt -= dfirst * j; } } else { if (len > MAX_INT_LEN) { // corrected (added) 2016 08 16 s = lsortingmZeroesPositive(s); len=s.length(); } if (len >= MAX_INT_LEN) { c = s.charAt(0); if (!Character.isDigit(c)) return false; dfirst = c-'0'; if (len > MAX_INT_LEN || dfirst > MAX_INT_FIRSTDIGIT) return false; } for (i = len - 1, j = 1; i >= 1; --i, j *= 10) { c = s.charAt(i); if (!Character.isDigit(c)) return false; rslt += (c-'0')*j; } if (len < MAX_INT_LEN) { c = s.charAt(i); if (!Character.isDigit(c)) return false; rslt += (c-'0')*j; } if (dfirst >= MAX_INT_FIRSTDIGIT && rslt > MAX_INT_LASTDEC) return false; rslt += dfirst*j; } intBox._n=rslt; return true; } // Get the value stored in an IntBoxSimple: public int get_n() { return _n; } public int v() { // alternative shorter version, v for "value" return _n; } // Make objects of IntBoxSimple (needed as constructors are not public): public static IntBoxSimple makeIntBoxSimple() { return new IntBoxSimple(); } public static IntBoxSimple makeIntBoxSimple(int integerNumber) { return new IntBoxSimple(integerNumber); } // constructors are not public(!=: protected IntBoxSimple() {} { _n=0; // default value an IntBoxSimple holds } protected IntBoxSimple(int integerNumber) { _n=integerNumber; } } 

Test / exemple de programme pour la classe IntBoxSimple:

 import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; public class IntBoxSimpleTest { public static void main (Ssortingng args[]) { IntBoxSimple ibs = IntBoxSimple.makeIntBoxSimple(); Ssortingng in = null; BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); do { System.out.printf( "Enter an integer number in the range %d to %d:%n", Integer.MIN_VALUE, Integer.MAX_VALUE); try { in = br.readLine(); } catch (IOException ex) {} } while(! IntBoxSimple.tryParse(in, ibs)); System.out.printf("The number you have entered was: %d%n", ibs.v()); } } 

Essayez avec une expression régulière et un argument de parameters par défaut

 public static int parseIntWithDefault(Ssortingng str, int defaultInt) { return str.matches("-?\\d+") ? Integer.parseInt(str) : defaultInt; } int testId = parseIntWithDefault("1001", 0); System.out.print(testId); // 1001 int testId = parseIntWithDefault("test1001", 0); System.out.print(testId); // 1001 int testId = parseIntWithDefault("-1001", 0); System.out.print(testId); // -1001 int testId = parseIntWithDefault("test", 0); System.out.print(testId); // 0 

si vous utilisez apache.commons.lang3 puis en utilisant NumberUtils :

 int testId = NumberUtils.toInt("test", 0); System.out.print(testId); // 0 

Je voudrais lancer une autre proposition qui fonctionne si on demande spécifiquement des entiers: utilisez simplement long et utilisez Long.MIN_VALUE pour les cas d’erreur. Ceci est similaire à l’approche utilisée pour les caractères dans Reader, où Reader.read () renvoie un entier compris entre 1 et 1 si le lecteur est vide.

Pour Float et Double, NaN peut être utilisé de manière similaire.

 public static long parseInteger(Ssortingng s) { try { return Integer.parseInt(s); } catch (NumberFormatException e) { return Long.MIN_VALUE; } } // ... long l = parseInteger("ABC"); if (l == Long.MIN_VALUE) { // ... error } else { int i = (int) l; } 

Vous ne devez pas utiliser les exceptions pour valider vos valeurs .

Pour un caractère unique, il existe une solution simple:

 Character.isDigit() 

Pour des valeurs plus longues, il est préférable d’utiliser certains utilitaires. NumberUtils fourni par Apache fonctionnerait parfaitement ici:

 NumberUtils.isNumber() 

Veuillez vérifier https://commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/apache/commons/lang/math/NumberUtils.html

Vous pouvez utiliser un object nul comme ceci:

 public class Convert { @SuppressWarnings({"UnnecessaryBoxing"}) public static final Integer NULL = new Integer(0); public static Integer convert(Ssortingng integer) { try { return Integer.valueOf(integer); } catch (NumberFormatException e) { return NULL; } } public static void main(Ssortingng[] args) { Integer a = convert("123"); System.out.println("a.equals(123) = " + a.equals(123)); System.out.println("a == NULL " + (a == NULL)); Integer b = convert("onetwothree"); System.out.println("b.equals(123) = " + b.equals(123)); System.out.println("b == NULL " + (b == NULL)); Integer c = convert("0"); System.out.println("equals(0) = " + c.equals(0)); System.out.println("c == NULL " + (c == NULL)); } } 

Le résultat de main dans cet exemple est:

 a.equals(123) = true a == NULL false b.equals(123) = false b == NULL true c.equals(0) = true c == NULL false 

De cette façon, vous pouvez toujours tester l’échec de la conversion mais toujours utiliser les résultats en tant qu’instances Integer. Vous pourriez également vouloir modifier le nombre que NULL représente (≠ 0).