Buena forma de encapsular Integer.parseInt ()

93

Tengo un proyecto en el que solemos Integer.parseInt()convertir un String en un int. Cuando algo sale mal (por ejemplo, Stringno es un número sino la letra a, o lo que sea), este método generará una excepción. Sin embargo, si tengo que manejar excepciones en mi código en todas partes, esto comienza a verse muy feo muy rápidamente. Me gustaría poner esto en un método, sin embargo, no tengo ni idea de cómo devolver un valor limpio para mostrar que la conversión salió mal.

En C ++, podría haber creado un método que aceptara un puntero a un int y dejara que el método devolviera verdadero o falso. Sin embargo, hasta donde yo sé, esto no es posible en Java. También podría crear un objeto que contenga una variable verdadero / falso y el valor convertido, pero esto tampoco parece ideal. Lo mismo ocurre con un valor global, y esto podría darme algunos problemas con el subproceso múltiple.

Entonces, ¿hay una forma limpia de hacer esto?

Caballo malo
fuente
Los caracteres de la cadena deben ser todos los dígitos decimales, excepto que el primer carácter ... . En lugar de manejar excepciones en todas partes del código, simplemente verifique el formato de cadena antes de llamar al método de análisis.
Lightman
Es casi imposible escribir una expresión regular que capture todos los enteros válidos de 32 bits con signo y ninguno de los inválidos. 2147483647 es legal, intmientras que 2147483648 no lo es.
Seva Alekseyev

Respuestas:

142

Puede devolver un en Integerlugar de un int, volviendo nullen caso de error de análisis.

Sin embargo, es una pena que Java no proporcione una forma de hacer esto sin que se produzca una excepción internamente; puede ocultar la excepción (capturándola y devolviendo nulo), pero aún podría ser un problema de rendimiento si está analizando cientos de miles de bits de datos proporcionados por el usuario.

EDITAR: Código para tal método:

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

Tenga en cuenta que no estoy seguro de lo que hará esto si textes nulo. Debe tener en cuenta que: si representa un error (es decir, su código puede pasar un valor no válido, pero nunca debe pasar nulo), entonces lanzar una excepción es apropiado; si no representa un error, probablemente debería devolver nulo como lo haría con cualquier otro valor no válido.

Originalmente, esta respuesta usaba el new Integer(String)constructor; ahora usaInteger.parseInt y una operación de boxeo; de esta forma los valores pequeños terminarán encajonándose en los Integerobjetos en caché , haciéndolo más eficiente en esas situaciones.

Jon Skeet
fuente
1
¿Cómo ayuda esto? El sitio de la llamada requerirá: <b> temp = tryParse (...); if (temp! = Null) {target = temp; } else {hacer la acción de recuperación}; </b> con una probable excepción de lanzamiento en la parte de recuperación. En la formulación original, el sitio de llamada requiere <b> try target = (...). ParseInt; catch (...) {do recovery action} </b> con una excepción de lanzamiento trivial en la recuperación que se está implementando simplemente eliminando la cláusula catch. ¿Cómo la solución propuesta hace que esto sea más fácil de entender (tiene un truco de magia) o reduce la cantidad de código de alguna manera?
Ira Baxter
15
En general, es más limpio codificar para verificar nullreferencias que manejar excepciones de forma regular.
Adam Maras
Es incluso más limpio evitar pasar nulos como valores, pero en su lugar indicar de alguna manera que ha ocurrido un error; las excepciones no deben usarse para el control de flujo.
Esko
2
@Steve Kuo: ¿Por qué? ¿Dónde está el beneficio? ¿Ambos crean un nuevo entero cada vez? En todo caso, estoy tentado a usar Integer.parseInt y dejar que el autoboxing se encargue de ello, para aprovechar la caché para valores pequeños.
Jon Skeet
1
@Vlasec Y no solo opcionales, sino versiones especializadas para primitivas, como OptionalInt.
Joshua Taylor
37

¿Qué comportamiento esperas cuando no es un número?

Si, por ejemplo, a menudo tiene un valor predeterminado para usar cuando la entrada no es un número, entonces un método como este podría ser útil:

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

Se pueden escribir métodos similares para un comportamiento predeterminado diferente cuando la entrada no se puede analizar.

Joachim Sauer
fuente
29

En algunos casos, debe manejar los errores de análisis como situaciones de falla rápida, pero en otros casos, como la configuración de la aplicación, prefiero manejar la entrada faltante con valores predeterminados usando Apache Commons Lang 3 NumberUtils .

int port = NumberUtils.toInt(properties.getProperty("port"), 8080);
Bryan W. Wagner
fuente
La mayor parte del tiempo ya está usando apache commons en su proyecto debido a otras razones (como StringUtils), eso se vuelve útil.
Ratata Tata
16

Para evitar el manejo de excepciones, use una expresión regular para asegurarse de tener todos los dígitos primero:

//Checking for Regular expression that matches digits
if(value.matches("\\d+")) {
     Integer.parseInt(value);
}
Daddyboy
fuente
Gracias por su respuesta. Leí la mayoría de las respuestas en esta página, yo personalmente había escrito la solución try / catch. sin embargo, este es mi problema, aunque pequeño, con esa solución. la mayoría de los IDE se ahogarán al analizar el flujo de su código cuando intente / capture dentro de un bucle. es por eso que lo que necesitaba era una solución sin el try / catch.
victor n.
4
Ten cuidado. La expresión regular con coincide con un entero que comienza con 0, que luego arrojará una NumberFormatException. Prueba esto ^ (?: [1-9] \ d * | 0) $ de stackoverflow.com/questions/12018479/…
Goose
5
Esta expresión regular en particular no manejaría números negativos.
Brad Cupit
7
Además, esto no cubre los rangos de números que están fuera de los límites de números enteros
Mohammad Yahia
10

Hay Ints.tryParse()en Guayaba . No lanza una excepción en una cadena no numérica, sin embargo, lanza una excepción en una cadena nula.

husayt
fuente
4

Después de leer las respuestas a la pregunta, creo que encapsular o envolver el método parseInt no es necesario, tal vez ni siquiera sea una buena idea.

Podría devolver 'nulo' como sugirió Jon, pero eso es más o menos reemplazando una construcción try / catch por una verificación nula. Solo hay una pequeña diferencia en el comportamiento si 'olvida' el manejo de errores: si no detecta la excepción, no hay asignación y la variable del lado izquierdo mantiene el valor anterior. Si no prueba el valor nulo, probablemente la JVM (NPE) lo golpee.

La sugerencia de bostezo me parece más elegante, porque no me gusta devolver nulo para señalar algunos errores o estados excepcionales. Ahora debe verificar la igualdad referencial con un objeto predefinido, que indica un problema. Pero, como otros argumentan, si nuevamente 'olvida' verificar y una Cadena no se puede analizar, el programa continúa con el int envuelto dentro de su objeto 'ERROR' o 'NULL'.

La solución de Nikolay está aún más orientada a objetos y también funcionará con métodos parseXXX de otras clases contenedoras. Pero al final, simplemente reemplazó la excepción NumberFormatException por una excepción OperationNotSupported; nuevamente, necesita un try / catch para manejar entradas que no se pueden analizar.

Por lo tanto, es mi conclusión no encapsular el método parseInt simple. Solo encapsularía si pudiera agregar también algún manejo de errores (dependiente de la aplicación).

Andreas Dolk
fuente
4

Quizás puedas usar algo como esto:

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
fuente
Me gusta tu solución usando el patrón quizás. Very haskelly;)
rodrigoelp
1
Esta solución ahora está desactualizada ya que hay java.util.Optional desde Java 8 :)
Vlasec
2

También puede replicar el comportamiento de C ++ que desee de manera muy simple

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;
    }
}

Usaría el método así:

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

Después de eso, la variable resultes verdadera si todo salió bien ybyRef[0] contiene el valor analizado.

Personalmente, me quedaría con la excepción.


fuente
2

La respuesta dada por Jon Skeet está bien, pero no me gusta devolver un nullobjeto Integer. Encuentro esto confuso de usar. Desde Java 8 hay una mejor opción (en mi opinión), usando OptionalInt:

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

Esto hace que sea explícito que debe manejar el caso en el que no hay ningún valor disponible. Preferiría que este tipo de función se agregara a la biblioteca java en el futuro, pero no sé si eso sucederá alguna vez.

Bagazo
fuente
1

Mi Java está un poco oxidado, pero déjame ver si puedo indicarte la dirección correcta:

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 su valor de retorno es null, tiene un valor incorrecto. De lo contrario, tiene un archivo Integer.

Adam Maras
fuente
El OP quiere el resultado de la conversión (como referencia) más una indicación de que la conversión fue exitosa (o no).
bostezo
1
@yawn: Y una referencia nula da exactamente esa indicación.
Jon Skeet
@John Skeet: correcto, pero leí su intención de manera diferente. Escribió algo como usar un objeto intermedio para diferenciar entre éxito / fracaso + valor. Viniendo de un fondo de C ++, pensé que si él quisiera usar null (en lugar de un objeto), no habría hecho la pregunta en primer lugar.
bostezo
Hay una gran diferencia entre "valor" y "objeto". Una referencia nula es un valor limpio, pero no un objeto.
Jon Skeet
1. No hay Integer.tryParseen la Integerclase estándar de Java . 2. Hacerlo new Integeres innecesario (y se recomienda no hacerlo) ya que Java hace el boxeo y el desempaquetado automáticamente. Tu Java no solo está un poco oxidado, está muy oxidado.
ADTC
1

¿Qué hay de bifurcar el método parseInt ?

Es fácil, simplemente copie y pegue el contenido en una nueva utilidad que devuelve Integero Optional<Integer>reemplace los lanzamientos con devoluciones. Parece que no hay excepciones en el código subyacente, pero es mejor comprobar .

Al omitir todo el manejo de excepciones, puede ahorrar algo de tiempo en entradas no válidas. Y el método está ahí desde JDK 1.0, por lo que no es probable que tenga que hacer mucho para mantenerlo actualizado.

Vlasec
fuente
0

Le sugiero que considere un método como

 IntegerUtilities.isValidInteger(String s)

que luego implementa como mejor le parezca. Si desea que el resultado se lleve de regreso, tal vez porque usa Integer.parseInt () de todos modos, puede usar el truco de la matriz.

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

donde establece el resultado [0] en el valor entero encontrado en el proceso.

Thorbjørn Ravn Andersen
fuente
0

Esto es algo similar a la solución 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());
 }

El método principal demuestra el código. Otra forma de implementar la interfaz del analizador, obviamente, sería simplemente establecer "\ D +" desde la construcción y hacer que los métodos no hagan nada.

Carl
fuente
0

Usted podría rodar su propia, pero es igual de fácil de uso de bienes comunes lang StringUtils.isNumeric() método . Utiliza Character.isDigit () para iterar sobre cada carácter de la Cadena.

James Bassett
fuente
Entonces no funcionaría si el dígito contiene un número demasiado grande. Integer.parseInt lanza una excepción para números mayores que Integer.MAX_VALUE (lo mismo, por supuesto, para el lado negativo).
Searles
0

La forma en que manejo este problema es recursiva. Por ejemplo, al leer datos de la consola:

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
fuente
0

Para evitar una excepción, puede utilizar el Format.parseObjectmétodo de Java . El siguiente código es básicamente una versión simplificada de la clase IntegerValidator de 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;
}

Puede utilizar AtomicIntegero elint[] truco de matriz según sus preferencias.

Aquí está mi prueba que lo usa:

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

Yo también estaba teniendo el mismo problema. Este es un método que escribí para pedirle al usuario una entrada y no aceptar la entrada a menos que sea un número entero. Tenga en cuenta que soy un principiante, así que si el código no funciona como se esperaba, ¡culpe a mi inexperiencia!

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
fuente
1
No use System.out.println (es una mala práctica). El problema de usarlo es que su programa esperará hasta que termine la impresión. El mejor enfoque es utilizar un marco de registro.
Omar Hrynkiewicz
0

Esta es una respuesta a la pregunta 8391979, "¿Java tiene un int.tryparse que no arroja una excepción para datos incorrectos? [Duplicar]", que está cerrada y vinculada a esta pregunta.

Edición 2016 08 17: Se agregaron métodos ltrimZeroes y se los llamó en tryParse (). Sin ceros a la izquierda en numberString puede dar resultados falsos (ver comentarios en el código). Ahora también hay un método público estático String ltrimZeroes (String numberString) que funciona para "números" positivos y negativos (END Edit)

A continuación, encontrará una clase Wrapper (boxing) rudimentaria para int con un método tryParse () optimizado de alta velocidad (similar al de C #) que analiza la cadena en sí y es un poco más rápido 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;
    }
}

Programa de prueba / ejemplo para la clase 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
fuente
0

Pruebe con la expresión regular y el argumento de parámetros predeterminados

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 está usando apache.commons.lang3 entonces usando NumberUtils :

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

Me gustaría incluir otra propuesta que funcione si uno solicita específicamente números enteros: simplemente use long y use Long.MIN_VALUE para casos de error. Esto es similar al enfoque que se usa para los caracteres en Reader, donde Reader.read () devuelve un número entero en el rango de un carácter o -1 si el lector está vacío.

Para Float y Double, NaN se puede utilizar de forma similar.

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
fuente
0

Teniendo en cuenta las respuestas existentes, he copiado y pegado el código fuente mejorado de Integer.parseIntpara hacer el trabajo y mi solución

  • no utiliza try-catch potencialmente lento (a diferencia de Lang 3 NumberUtils ),
  • no usa expresiones regulares que no pueden capturar números demasiado grandes,
  • evita el boxeo (a diferencia de Guayaba Ints.tryParse()),
  • no requiere ninguna asignación (a diferencia de int[], Box, OptionalInt),
  • acepta CharSequenceuna parte o parte de ella en lugar de un todo String,
  • puede usar cualquier base que Integer.parseIntpueda, es decir, [2,36],
  • no depende de ninguna biblioteca.

El único inconveniente es que no hay diferencia entre toIntOfDefault("-1", -1)y 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
fuente
0

Quizás alguien esté buscando un enfoque más genérico, ya que Java 8 existe el Paquete java.util.functionque permite definir Funciones de Proveedor. Podría tener una función que tome un proveedor y un valor predeterminado de la siguiente manera:

public static <T> T tryGetOrDefault(Supplier<T> supplier, T defaultValue) {
    try {
        return supplier.get();
    } catch (Exception e) {
        return defaultValue;
    }
}

Con esta función, puede ejecutar cualquier método de análisis o incluso otros métodos que podrían generar una excepción y, al mismo tiempo, asegurarse de que no se pueda generar ninguna excepción:

Integer i = tryGetOrDefault(() -> Integer.parseInt(stringValue), 0);
Long l = tryGetOrDefault(() -> Long.parseLong(stringValue), 0l);
Double d = tryGetOrDefault(() -> Double.parseDouble(stringValue), 0d);
A. Markóczy
fuente
-1

Puede usar un objeto nulo así:

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));

    }

}

El resultado de main en este ejemplo es:

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

De esta manera, siempre puede probar la conversión fallida pero seguir trabajando con los resultados como instancias de Integer. También puede modificar el número que representa NULL (≠ 0).

bostezo
fuente
¿Qué pasa si 'String integer' es el literal String "0"? Nunca sabrá si hubo una entrada inválida.
Bart Kiers
Supongo que eso depende de si el operador == para dos enteros compara valores o referencias. Si compara valores, el problema existe. Si compara referencias, funcionaría de manera equivalente a mi respuesta.
Adam Maras
¿Por qué el voto negativo? Mi respuesta es correcta y ofrece la ventaja (sobre nula) de que siempre trata con una instancia válida de Integer (en lugar de nula) lo que le libera de tener que lidiar con NPE.
bostezo
Sin embargo, es útil distinguir nulo de un entero real . Usted debe estar probando el resultado de nulidad, para saber si el análisis sintáctico tuvo éxito o no. Ocultar ese objeto detrás y utilizable es una receta para problemas, en mi opinión.
Jon Skeet
Más votos negativos, ¡interesante! Ya que soy nuevo en SO y todos, ¿podría alguno de los votantes explicarme el por qué?
bostezo
-1

No debe usar Excepciones para validar sus valores .

Para un solo carácter, hay una solución simple:

Character.isDigit()

Para valores más largos, es mejor usar algunas utilidades. NumberUtils proporcionados por Apache funcionaría perfectamente aquí:

NumberUtils.isNumber()

Consulte https://commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/apache/commons/lang/math/NumberUtils.html

Bogdan Aksonenko
fuente
«Comprueba si la cadena es un número Java válido. Los números válidos incluyen hexadecimales marcados con el calificador 0x, notación científica y números marcados con un calificador de tipo (por ejemplo, 123L). » Esto no es con lo que se puede analizar Integer.parseInt.
Miha_x64