Bon moyen d'encapsuler Integer.parseInt ()

88

J'ai un projet dans lequel nous utilisons souvent Integer.parseInt()pour convertir une chaîne en un int. Lorsque quelque chose ne va pas (par exemple, le Stringn'est pas un nombre mais une lettre a, ou autre), cette méthode lèvera 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 renvoyer une valeur propre afin de montrer que la conversion s'est mal passée.

En C ++, j'aurais pu créer une méthode qui accepte un pointeur vers un int et laisse la méthode elle-même retourner true ou false. Cependant, pour autant que je sache, ce n'est pas possible en Java. Je pourrais également créer un objet contenant une variable vrai / faux et la valeur convertie, mais cela ne semble pas non plus idéal. La même chose vaut pour une valeur globale, et cela pourrait me poser quelques problèmes avec le multithreading.

Alors, y a-t-il un moyen propre de faire cela?

Mauvais cheval
la source
Les caractères de la chaîne doivent tous être des chiffres décimaux, sauf que le premier caractère ... . Au lieu de gérer les exceptions partout dans le code, vérifiez simplement le format de la chaîne avant d'appeler la méthode d'analyse.
Lightman
Il est pratiquement impossible d'écrire une expression régulière qui capturera tous les entiers signés 32 bits valides et aucun des entiers invalides. 2147483647 est une valeur légale intalors que 2147483648 ne l'est pas.
Seva Alekseyev

Réponses:

140

Vous pouvez retourner un Integerau lieu d'un int, en retournantnull en cas d'échec de l'analyse.

C'est dommage que Java ne fournisse pas un moyen de le faire sans qu'une exception soit lancée en interne - vous pouvez masquer l'exception (en l'attrapant et en renvoyant null), mais cela pourrait toujours être un problème de performances si vous analysez des centaines de milliers de bits de données fournies par l'utilisateur.

EDIT: Code pour une telle méthode:

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

Notez que je ne suis pas sûr du haut de ma tête ce que cela fera si textest nul. Vous devriez considérer que - si cela représente un bogue (c'est-à-dire que votre code peut bien passer une valeur invalide, mais ne devrait jamais passer null), alors lancer une exception est approprié; si cela ne représente pas un bogue, vous devriez probablement simplement renvoyer null comme vous le feriez pour toute autre valeur invalide.

À l'origine, cette réponse utilisait le new Integer(String)constructeur; il utilise maintenant Integer.parseIntet une opération de boxe; de cette façon, les petites valeurs finiront par être encadrées dans des Integerobjets mis en cache , ce qui le rendra plus efficace dans ces situations.

Jon Skeet
la source
1
Comment cela aide-t-il? Le site d'appel nécessitera: <b> temp = tryParse (...); if (temp! = Null) {cible = temp; } else {do ​​recovery action}; </b> avec une probable exception throw dans la partie restauration. Dans la formulation d'origine, le site d'appel nécessite <b> try target = (...). ParseInt; catch (...) {do recovery action} </b> avec une exception throw triviale dans la restauration implémentée en supprimant simplement la clause catch. Comment la solution proposée rend-elle cela plus simple à comprendre (elle a un tour de magie) ou réduit-elle la quantité de code de quelque manière que ce soit?
Ira Baxter le
14
Il est généralement plus propre de coder pour vérifier les nullréférences que de gérer régulièrement les exceptions.
Adam Maras
Il est encore plus simple d'éviter de passer des valeurs nulles en tant que valeurs, mais plutôt d'indiquer qu'une erreur s'est produite; les exceptions ne doivent pas être utilisées pour le contrôle de flux.
Esko du
2
@Steve Kuo: Pourquoi? Où est l'avantage? Ils créent tous les deux un nouvel Integer à chaque fois? Si quoi que ce soit, je suis tenté d'utiliser Integer.parseInt et de laisser l'autoboxing s'en occuper, pour profiter du cache pour les petites valeurs.
Jon Skeet
1
@Vlasec Et pas seulement des versions facultatives, mais spécialisées pour les primitives, comme OptionalInt.
Joshua Taylor
36

À quel comportement attendez-vous quand ce n'est pas un nombre?

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(String number, int defaultVal) {
  try {
    return Integer.parseInt(number);
  } catch (NumberFormatException e) {
    return defaultVal;
  }
}

Des méthodes similaires peuvent être écrites pour un comportement par défaut différent lorsque l'entrée ne peut pas être analysée.

Joachim Sauer
la source
29

Dans certains cas, vous devez gérer les erreurs d'analyse comme des situations de défaillance rapide, mais dans d'autres cas, tels que la configuration de l'application, je préfère gérer les entrées manquantes avec des valeurs par défaut à l'aide d' Apache Commons Lang 3 NumberUtils .

int port = NumberUtils.toInt(properties.getProperty("port"), 8080);
Bryan W. Wagner
la source
La plupart du temps, vous utilisez déjà apache commons dans votre projet pour d'autres raisons (comme StringUtils), cela devient pratique.
Ratata Tata
17

Pour éviter de gérer les exceptions, utilisez une expression régulière pour vous assurer que vous avez tous les chiffres en premier:

//Checking for Regular expression that matches digits
if(value.matches("\\d+")) {
     Integer.parseInt(value);
}
Papa
la source
Merci pour votre réponse. J'ai lu la plupart des réponses sur cette page, j'avais personnellement écrit la solution try / catch. cependant, voici mon problème, bien que petit, avec cette solution. la plupart des IDE vont s'étouffer en analysant le flux de votre code lorsque vous avez un try / catch dans une boucle. c'est pourquoi une solution sans try / catch était ce dont j'avais besoin.
victor n.
4
Faites attention. L'expression régulière avec correspond à un entier commençant par 0 qui lèvera alors une NumberFormatException. Essayez ceci ^ (?: [1-9] \ d * | 0) $ de stackoverflow.com/questions/12018479/…
Goose
4
Cette regex particulière ne gérerait pas les nombres négatifs.
Brad Cupit
6
cela ne couvre pas non plus les plages de nombres qui sont hors des limites entières
Mohammad Yahia
10

Il y Ints.tryParse()en a à Goyave . Il ne lève pas d'exception sur une chaîne non numérique, mais il renvoie une exception sur une chaîne nulle.

Husayt
la source
4

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

Vous pouvez retourner 'null' comme Jon l'a suggéré, mais cela remplace plus ou moins une construction try / catch par une vérification null. Il y a juste une légère différence sur le comportement si vous «oubliez» la gestion des erreurs: si vous n'attrapez 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 bâillement me paraît plus élégante, car je n'aime pas renvoyer null pour signaler des erreurs ou des états exceptionnels. Vous devez maintenant vérifier l'égalité référentielle avec un objet prédéfini, cela indique un problème. Mais, comme d'autres le soutiennent, si à nouveau vous «oubliez» de vérifier et qu'une chaîne est impossible à analyser, le programme continue avec l'int enveloppé dans votre objet «ERROR» ou «NULL».

La solution de Nikolay est encore plus orientée objet et fonctionnera également avec les méthodes parseXXX d'autres classes wrapper. Mais à la fin, il vient de remplacer le 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 simple parseInt. Je n'encapsulerais que si je pouvais également ajouter une gestion des erreurs (en fonction de l'application).

Andreas Dolk
la source
4

Vous pouvez peut-être utiliser quelque chose comme ceci:

public class Test {
public interface Option<T> {
    T get();

    T getOrElse(T def);

    boolean hasValue();
}

final static class Some<T> implements Option<T> {

    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<T> implements Option<T> {

    @Override
    public T get() {
        throw new UnsupportedOperationException();
    }

    @Override
    public T getOrElse(T def) {
        return def;
    }

    @Override
    public boolean hasValue() {
        return false;
    }

}

public static Option<Integer> parseInt(String s) {
    Option<Integer> result = new None<Integer>();
    try {
        Integer value = Integer.parseInt(s);
        result = new Some<Integer>(value);
    } catch (NumberFormatException e) {
    }
    return result;
}

}
Nikolay Ivanov
la source
J'aime votre solution utilisant le modèle peut-être. Very haskelly;)
rodrigoelp
1
Cette solution est désormais obsolète car il existe java.util.Optional depuis Java 8 :)
Vlasec
2

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

public static boolean parseInt(String 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 resultest vraie si tout s'est bien passé etbyRef[0] contient la valeur analysée.

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


la source
2

La réponse donnée par Jon Skeet est bonne, mais je n'aime pas rendre un nullobjet Integer. Je trouve cela déroutant à utiliser. Depuis Java 8, il existe une meilleure option (à mon avis), en utilisant le OptionalInt:

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

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

Marc
la source
2

Si vous utilisez Java 8 ou une version ultérieure, vous pouvez utiliser une bibliothèque que je viens de publier: https://github.com/robtimus/try-parse . Il prend en charge int, long et boolean qui ne repose pas sur la capture d'exceptions. Contrairement à Ints.tryParse de Guava, il renvoie OptionalInt / OptionalLong / Optional, un peu comme dans https://stackoverflow.com/a/38451745/1180351 mais plus efficace.

Rob Spoor
la source
1

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(String str) {
        Integer n = null;

        try {
            n = new Integer(Integer.tryParse(str));
        } catch (NumberFormatException ex) {
            // leave n null, the string is invalid
        }

        return n;
    }

}

Si votre valeur de retour est null, vous avez une mauvaise valeur. Sinon, vous disposez d'un fichier Integer.

Adam Maras
la source
L'OP veut le résultat de la conversion (comme référence) plus une indication que la conversion a réussi (ou non).
bâillement le
1
@yawn: Et une référence nulle donne exactement cette indication.
Jon Skeet
@John Skeet: correct mais j'ai lu son intention différemment. Il a écrit quelque chose comme utiliser un objet intermédiaire pour différencier succès / échec + valeur. Venant d'un arrière-plan C ++, j'ai pensé que s'il voulait utiliser null (au lieu d'un objet), il n'aurait pas posé la question en premier lieu.
bâillement le
Il y a une différence majeure entre «valeur» et «objet». Une référence nulle est une valeur propre, mais pas un objet.
Jon Skeet
1. Il n'y a pas Integer.tryParsedans la Integerclasse Java standard . 2. Faire new Integerest inutile (et déconseillé) car Java fait automatiquement la boxe et le déballage. Votre Java n'est pas seulement un peu rouillé, il est très rouillé.
ADTC
1

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

C'est facile, il suffit de copier-coller le contenu dans un nouvel utilitaire qui renvoie Integerou Optional<Integer>et de remplacer les lancers par des retours. Il semble qu'il n'y ait pas d'exceptions dans le code sous-jacent, mais mieux vérifier .

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 ayez à faire grand-chose pour la maintenir à jour.

Vlasec
la source
0

Je vous suggère d'envisager une méthode comme

 IntegerUtilities.isValidInteger(String 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 de toute façon Integer.parseInt () - vous pouvez utiliser l'astuce du tableau.

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

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

Thorbjørn Ravn Andersen
la source
0

Ceci est un peu similaire à la solution de Nikolay:

 private static class Box<T> {
  T me;
  public Box() {}
  public T get() { return me; }
  public void set(T fromParse) { me = fromParse; }
 }

 private interface Parser<T> {
  public void setExclusion(String regex);
  public boolean isExcluded(String s);
  public T parse(String s);
 }

 public static <T> boolean parser(Box<T> ref, Parser<T> p, String toParse) {
  if (!p.isExcluded(toParse)) {
   ref.set(p.parse(toParse));
   return true;
  } else return false;
 }

 public static void main(String args[]) {
  Box<Integer> a = new Box<Integer>();
  Parser<Integer> intParser = new Parser<Integer>() {
   String myExclusion;
   public void setExclusion(String regex) {
    myExclusion = regex;
   }
   public boolean isExcluded(String s) {
    return s.matches(myExclusion);
   }
   public Integer parse(String 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 dé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 laisser les méthodes ne rien faire.

Carl
la source
0

Vous pouvez lancer la vôtre, mais c'est tout aussi simple d'utiliser la StringUtils.isNumeric() méthode de commons lang . Il utilise Character.isDigit () pour parcourir chaque caractère de la chaîne.

James Bassett
la source
Ensuite, cela ne fonctionnerait pas si le chiffre contient un nombre trop grand. Integer.parseInt lève une exception pour les nombres plus grands que Integer.MAX_VALUE (même chose bien sûr pour le côté négatif).
Searles
0

La manière dont je gère 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;
}
Boboman
la source
0

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

public static boolean tryParse(String 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 utiliser AtomicIntegerouint[] astuce tableau en fonction de 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]);
Josh Unger
la source
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 n'accepter l'entrée que si elle est un entier. Veuillez noter que je suis un débutant donc si le code ne fonctionne pas comme prévu, blâmez mon inexpérience!

private int numberValue(String 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((String) 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();
}
Abhinav Mathur
la source
1
N'utilisez pas System.out.println (c'est une mauvaise pratique). Le problème avec son utilisation, c'est que votre programme attendra que l'impression soit terminée. La meilleure approche consiste à utiliser un cadre de journalisation.
Omar Hrynkiewicz
0

Ceci est une réponse à la question 8391979, "Est-ce que java a un int.tryparse qui ne lève pas d'exception pour les mauvaises données? [Dupliquer]" qui est fermé et lié à cette question.

Edit 2016 08 17: Ajout des méthodes ltrimZeroes et les a appelées dans tryParse (). Sans zéros non significatifs dans numberString peut donner de faux résultats (voir les commentaires dans le code). Il existe maintenant aussi la méthode publique statique String ltrimZeroes (String numberString) qui fonctionne pour les «nombres» positifs et négatifs (END Edit)

Vous trouverez ci-dessous une classe rudimentaire Wrapper (boxing) pour int avec une méthode tryParse () hautement optimisée pour la vitesse (similaire à C #) qui analyse la chaîne elle-même et est un peu plus rapide que Integer.parseInt (String 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 (i. e. only once) or
    // already compiled into the code at compile time:
    public static final int MAX_INT_LEN =
            String.valueOf(Integer.MAX_VALUE).length();
    public static final int MIN_INT_LEN =
            String.valueOf(Integer.MIN_VALUE).length();
    public static final int MAX_INT_LASTDEC =
            Integer.parseInt(String.valueOf(Integer.MAX_VALUE).substring(1));
    public static final int MAX_INT_FIRSTDIGIT =
            Integer.parseInt(String.valueOf(Integer.MAX_VALUE).substring(0, 1));
    public static final int MIN_INT_LASTDEC =
            -Integer.parseInt(String.valueOf(Integer.MIN_VALUE).substring(2));
    public static final int MIN_INT_FIRSTDIGIT =
            Integer.parseInt(String.valueOf(Integer.MIN_VALUE).substring(1,2));
    // END The following statements...

    // ltrimZeroes() methods added 2016 08 16 (are required by tryParse() methods)
    public static String ltrimZeroes(String s) {
        if (s.charAt(0) == '-')
            return ltrimZeroesNegative(s);
        else
            return ltrimZeroesPositive(s);
    }
    protected static String ltrimZeroesNegative(String s) {
        int i=1;
        for ( ; s.charAt(i) == '0'; i++);
        return ("-"+s.substring(i));
    }
    protected static String ltrimZeroesPositive(String s) {
        int i=0;
        for ( ; s.charAt(i) == '0'; i++);
        return (s.substring(i));
    }

    public static boolean tryParse(String 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.trim(); // leading and trailing whitespace is allowed for String 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 = ltrimZeroesNegative(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 = ltrimZeroesPositive(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;
    }
}

Programme de test / exemple pour la classe IntBoxSimple:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class IntBoxSimpleTest {
    public static void main (String args[]) {
        IntBoxSimple ibs = IntBoxSimple.makeIntBoxSimple();
        String 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());
    }
}
Peter Sulzer
la source
0

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

public static int parseIntWithDefault(String 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, utilisez NumberUtils :

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

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

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

public static long parseInteger(String 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;
}
Searles
la source
0

Compte tenu des réponses existantes, j'ai copié-collé et amélioré le code source de Integer.parseIntpour faire le travail, et ma solution

  • n'utilise pas de try-catch potentiellement lent (contrairement à Lang 3 NumberUtils ),
  • n'utilise pas d'expressions rationnelles qui ne peuvent pas attraper de trop grands nombres,
  • évite la boxe (contrairement à Guava Ints.tryParse()),
  • ne nécessite pas d'allocations ( à la différence int[], Box, OptionalInt),
  • en accepte tout CharSequenceou partie au lieu d'un tout String,
  • peut utiliser n'importe quelle base qui Integer.parseIntpeut, ie [2,36],
  • ne dépend d'aucune bibliothèque.

Le seul inconvénient est qu'il n'y a pas de différence entre toIntOfDefault("-1", -1)et toIntOrDefault("oops", -1).

public static int toIntOrDefault(CharSequence s, int def) {
    return toIntOrDefault0(s, 0, s.length(), 10, def);
}
public static int toIntOrDefault(CharSequence s, int def, int radix) {
    radixCheck(radix);
    return toIntOrDefault0(s, 0, s.length(), radix, def);
}
public static int toIntOrDefault(CharSequence s, int start, int endExclusive, int def) {
    boundsCheck(start, endExclusive, s.length());
    return toIntOrDefault0(s, start, endExclusive, 10, def);
}
public static int toIntOrDefault(CharSequence s, int start, int endExclusive, int radix, int def) {
    radixCheck(radix);
    boundsCheck(start, endExclusive, s.length());
    return toIntOrDefault0(s, start, endExclusive, radix, def);
}
private static int toIntOrDefault0(CharSequence s, int start, int endExclusive, int radix, int def) {
    if (start == endExclusive) return def; // empty

    boolean negative = false;
    int limit = -Integer.MAX_VALUE;

    char firstChar = s.charAt(start);
    if (firstChar < '0') { // Possible leading "+" or "-"
        if (firstChar == '-') {
            negative = true;
            limit = Integer.MIN_VALUE;
        } else if (firstChar != '+') {
            return def;
        }

        start++;
        // Cannot have lone "+" or "-"
        if (start == endExclusive) return def;
    }
    int multmin = limit / radix;
    int result = 0;
    while (start < endExclusive) {
        // Accumulating negatively avoids surprises near MAX_VALUE
        int digit = Character.digit(s.charAt(start++), radix);
        if (digit < 0 || result < multmin) return def;
        result *= radix;
        if (result < limit + digit) return def;
        result -= digit;
    }
    return negative ? result : -result;
}
private static void radixCheck(int radix) {
    if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX)
        throw new NumberFormatException(
                "radix=" + radix + " ∉ [" +  Character.MIN_RADIX + "," + Character.MAX_RADIX + "]");
}
private static void boundsCheck(int start, int endExclusive, int len) {
    if (start < 0 || start > len || start > endExclusive)
        throw new IndexOutOfBoundsException("start=" + start + " ∉ [0, min(" + len + ", " + endExclusive + ")]");
    if (endExclusive > len)
        throw new IndexOutOfBoundsException("endExclusive=" + endExclusive + " > s.length=" + len);
}
Miha_x64
la source
-1

Vous pouvez utiliser un Null-Object comme ceci:

public class Convert {

    @SuppressWarnings({"UnnecessaryBoxing"})
    public static final Integer NULL = new Integer(0);

    public static Integer convert(String integer) {

        try {
            return Integer.valueOf(integer);
        } catch (NumberFormatException e) {
            return NULL;
        }

    }

    public static void main(String[] 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 la conversion échouée, mais toujours travailler avec les résultats en tant qu'instances Integer. Vous pouvez également modifier le nombre représenté par NULL (≠ 0).

bâillement
la source
Que faire si 'String integer' est le littéral String "0"? Vous ne saurez jamais s'il y avait une entrée non valide.
Bart Kiers
Je suppose que cela dépend du fait que l'opérateur == pour deux entiers compare des valeurs ou des références. S'il compare les valeurs, le problème existe. S'il compare des références, cela fonctionnerait d'une manière équivalente à ma réponse.
Adam Maras
Pourquoi le vote négatif? Ma réponse est correcte et offre l'avantage (sur null) que vous traitez toujours avec une instance valide d'Integer (au lieu de null) vous évitant d'avoir à traiter avec des NPE.
bâillement le
Distinguer nul d'un entier réel est cependant utile . Vous devriez tester le résultat pour la nullité, pour savoir si l'analyse a réussi ou non. Cacher cet objet derrière et autrement utilisable est une recette pour les problèmes, l'OMI.
Jon Skeet
Plus de votes négatifs - intéressant! Puisque / moi étant nouveau à SO et tous un des électeurs pourrait-il m'expliquer le pourquoi?
bâillement le
-1

Vous ne devez pas utiliser d'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

Bogdan Aksonenko
la source
«Vérifie si la chaîne est un numéro Java valide. Les nombres valides incluent les nombres hexadécimaux marqués du qualificatif 0x, la notation scientifique et les nombres marqués d'un qualificatif de type (par exemple 123L). » Ce n'est pas ce qui peut être analysé Integer.parseInt.
Miha_x64