Tengo un proyecto en el que solemos Integer.parseInt()
convertir un String en un int. Cuando algo sale mal (por ejemplo, String
no 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?
fuente
int
mientras que 2147483648 no lo es.Respuestas:
Puede devolver un en
Integer
lugar de unint
, volviendonull
en 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
text
es 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 losInteger
objetos en caché , haciéndolo más eficiente en esas situaciones.fuente
null
referencias que manejar excepciones de forma regular.¿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.
fuente
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);
fuente
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); }
fuente
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.fuente
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).
fuente
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; } }
fuente
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
result
es verdadera si todo salió bien ybyRef[0]
contiene el valor analizado.Personalmente, me quedaría con la excepción.
fuente
La respuesta dada por Jon Skeet está bien, pero no me gusta devolver un
null
objeto Integer. Encuentro esto confuso de usar. Desde Java 8 hay una mejor opción (en mi opinión), usandoOptionalInt
: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.
fuente
Si está usando Java 8 o superior, puede usar una biblioteca que acabo de publicar: https://github.com/robtimus/try-parse . Tiene soporte para int, long y boolean que no depende de la captura de excepciones. A diferencia de Ints.tryParse de Guava, devuelve OptionalInt / OptionalLong / Optional, muy parecido a https://stackoverflow.com/a/38451745/1180351 pero más eficiente.
fuente
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 archivoInteger
.fuente
Integer.tryParse
en laInteger
clase estándar de Java . 2. Hacerlonew Integer
es 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.¿Qué hay de bifurcar el método parseInt ?
Es fácil, simplemente copie y pegue el contenido en una nueva utilidad que devuelve
Integer
oOptional<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.
fuente
Le sugiero que considere un método como
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.
fuente
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.
fuente
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.fuente
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; }
fuente
Para evitar una excepción, puede utilizar el
Format.parseObject
mé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
AtomicInteger
o 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]);
fuente
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(); }
fuente
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()); } }
fuente
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
fuente
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; }
fuente
Teniendo en cuenta las respuestas existentes, he copiado y pegado el código fuente mejorado de
Integer.parseInt
para hacer el trabajo y mi soluciónInts.tryParse()
),int[]
,Box
,OptionalInt
),CharSequence
una parte o parte de ella en lugar de un todoString
,Integer.parseInt
pueda, es decir, [2,36],El único inconveniente es que no hay diferencia entre
toIntOfDefault("-1", -1)
ytoIntOrDefault("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); }
fuente
Quizás alguien esté buscando un enfoque más genérico, ya que Java 8 existe el Paquete
java.util.function
que 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);
fuente
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).
fuente
No debe usar Excepciones para validar sus valores .
Para un solo carácter, hay una solución simple:
Para valores más largos, es mejor usar algunas utilidades. NumberUtils proporcionados por Apache funcionaría perfectamente aquí:
Consulte https://commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/apache/commons/lang/math/NumberUtils.html
fuente
Integer.parseInt
.