Boa maneira de encapsular Integer.parseInt ()

Eu tenho um projeto em que muitas vezes usamos Integer.parseInt() para converter uma String para um int. Quando algo dá errado (por exemplo, o String não é um número, mas a letra a , ou qualquer outra coisa), esse método lançará uma exceção. No entanto, se eu tiver que lidar com exceções no meu código em todos os lugares, isso começa a parecer muito feio muito rapidamente. Eu gostaria de colocar isso em um método, no entanto, eu não tenho idéia de como retornar um valor limpo, a fim de mostrar que a conversão correu mal.

Em C ++ eu poderia ter criado um método que aceitasse um ponteiro para um int e permitisse que o método retornasse verdadeiro ou falso. No entanto, tanto quanto sei, isso não é possível em Java. Eu também poderia criar um object que contém uma variável true / false e o valor convertido, mas isso também não parece ideal. A mesma coisa vale para um valor global, e isso pode me dar alguns problemas com multithreading.

Então, há uma maneira limpa de fazer isso?

Você poderia retornar um Integer vez de um int , retornando null na falha de análise.

É uma pena que o Java não forneça uma maneira de fazer isso sem que haja uma exceção lançada internamente – você pode ocultar a exceção (capturando-a e retornando null), mas ainda pode ser um problema de desempenho se você estiver analisando centenas de milhares de bits de dados fornecidos pelo usuário.

EDIT: código para esse método:

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

Note que eu não tenho certeza do topo da minha cabeça o que isso fará se o text for nulo. Você deve considerar que – se ele representa um bug (ou seja, seu código pode passar um valor inválido, mas nunca deve passar nulo), então lançar uma exceção é apropriado; se não representar um bug, provavelmente você deve retornar null como faria para qualquer outro valor inválido.

Originalmente, essa resposta usava o new Integer(String) construtor new Integer(String) ; agora ele usa Integer.parseInt e uma operação de boxe; Dessa forma, valores pequenos acabarão sendo encheckboxdos em objects Integer armazenados em cache, tornando-os mais eficientes nessas situações.

Qual comportamento você espera quando não é um número?

Se, por exemplo, você costuma ter um valor padrão para usar quando a input não é um número, então um método como este poderia ser útil:

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

Métodos similares podem ser escritos para comportamento padrão diferente quando a input não pode ser analisada.

Em alguns casos, você deve manipular erros de análise como situações de falha rápida, mas em outros casos, como configuração de aplicativo, eu prefiro manipular a input ausente com valores padrão usando o Apache Commons Lang 3 NumberUtils .

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

Para evitar manipular exceções, use uma expressão regular para garantir que você tenha todos os dígitos primeiro:

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

Ints.tryParse() em goiaba . Ele não lança exceção em uma string não numérica, no entanto, ele lança uma exceção na string nula.

Depois de ler as respostas à pergunta, acho que encapsular ou envolver o método parseInt não é necessário, talvez nem seja uma boa ideia.

Você poderia retornar ‘null’ como Jon sugeriu, mas isso é mais ou menos replace uma construção try / catch por uma verificação nula. Há apenas uma pequena diferença no comportamento se você ‘esquecer’ o tratamento de erros: se você não capturar a exceção, não há atribuição e a variável do lado esquerdo mantém o valor antigo. Se você não testar null, provavelmente será atingido pela JVM (NPE).

A sugestão do bocejo parece mais elegante para mim, porque eu não gosto de retornar null para sinalizar alguns erros ou estados excepcionais. Agora você precisa verificar a igualdade referencial com um object predefinido, que indica um problema. Mas, como os outros argumentam, se mais uma vez você ‘esquecer’ de checar e uma String não pode ser analisada, o programa continua com o int embrulhado dentro do seu object ‘ERROR’ ou ‘NULL’.

A solução de Nikolay é ainda mais orientada a objects e também funcionará com methods parseXXX de outras classs de wrapper. Mas no final, ele acabou de replace o NumberFormatException por uma exceção OperationNotSupported – novamente, você precisa de um try / catch para manipular inputs não comparáveis.

Então, é minha conclusão não encapsular o método simples parseInt. Eu apenas encapsularia se eu pudesse adicionar alguns erros de aplicação (dependendo do aplicativo) também.

Pode ser que você possa usar algo assim:

 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(String s) { Option result = new None(); try { Integer value = Integer.parseInt(s); result = new Some(value); } catch (NumberFormatException e) { } return result; } } 

Você também pode replicar o comportamento de C ++ que você quer muito simplesmente

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

Você usaria o método da seguinte forma:

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

Depois disso, o result da variável é verdadeiro se tudo byRef[0] certo e byRef[0] contém o valor analisado.

Pessoalmente, gostaria de pegar a exceção.

Meu Java está um pouco enferrujado, mas deixe-me ver se consigo apontar na direção certa:

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

Se o seu valor de retorno é null , você tem um valor ruim. Caso contrário, você tem um Integer válido.

Que tal bifurcar o método parseInt ?

É fácil, basta copiar e colar o conteúdo em um novo utilitário que retorna Integer ou Optional e replace throws por retornos. Parece que não há exceções no código subjacente, mas é melhor verificar .

Ignorando todo o material de tratamento de exceção, você pode economizar algum tempo em inputs inválidas. E o método está lá desde o JDK 1.0, então não é provável que você tenha que fazer muito para mantê-lo atualizado.

Eu sugiro que você considere um método como

  IntegerUtilities.isValidInteger(String s) 

que você implementa como achar melhor. Se você quer que o resultado seja carregado – talvez porque você use Integer.parseInt () de qualquer maneira – você pode usar o truque de array.

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

onde você define o resultado [0] para o valor inteiro encontrado no processo.

Isto é um pouco semelhante à solução 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(String regex); public boolean isExcluded(String s); public T parse(String s); } public static  boolean parser(Box ref, Parser p, String toParse) { if (!p.isExcluded(toParse)) { ref.set(p.parse(toParse)); return true; } else return false; } public static void main(String args[]) { Box a = new Box(); Parser intParser = new Parser() { 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()); } 

O método principal demonstra o código. Outra forma de implementar a interface Parser seria obviamente apenas definir “\ D +” a partir da construção e fazer com que os methods não façam nada.

Você pode fazer o seu próprio, mas é tão fácil usar o método StringUtils.isNumeric() do lang do StringUtils.isNumeric() . Ele usa Character.isDigit () para iterar sobre cada caractere na String.

A maneira como lidei com esse problema é recursivamente. Por exemplo, ao ler dados do 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; } 

Para evitar uma exceção, você pode usar o método Format.parseObject do Java. O código abaixo é basicamente uma versão simplificada da class IntegerValidator do 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; } 

Você pode usar o AtomicInteger ou o truque de matriz int[] dependendo da sua preferência.

Aqui está o meu teste que usa isso -

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

Eu também estava tendo o mesmo problema. Este é um método que escrevi para pedir ao usuário uma input e não aceitar a input, a menos que seja um inteiro. Por favor, note que eu sou um iniciante por isso, se o código não está funcionando como esperado, culpe minha inexperiência!

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

A resposta dada por Jon Skeet é boa, mas eu não gosto de devolver um object inteiro null . Eu acho isso confuso de usar. Desde o Java 8 existe uma opção melhor (na minha opinião), usando o OptionalInt :

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

Isso torna explícito que você precisa manipular o caso em que nenhum valor está disponível. Eu preferiria que esse tipo de function fosse adicionado à biblioteca java no futuro, mas não sei se isso acontecerá.

Esta é uma resposta à pergunta 8391979, “O java tem um int.tryparse que não lança uma exceção para dados inválidos? [Duplicado]” que está fechado e vinculado a essa pergunta.

Editar 2016 08 17: Adicionados methods ltrimZeroes e chamados em tryParse (). Sem zeros à esquerda em numberString pode dar resultados falsos (veja comentários no código). Existe agora também o método público estático String ltrimZeroes (String numberString) que funciona para “números” positivos e negativos (END Edit)

Abaixo, você encontra uma class Wrapper (boxe) rudimentar para int com um método tryParse () altamente otimizado em velocidade (semelhante ao C #) que analisa a string em si e é um pouco mais rápido que Integer.parseInt (String s) do 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 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 teste / exemplo para a class 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()); } } 

Tente com expressão regular e argumento de parâmetros padrão

 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 

Se você estiver usando apache.commons.lang3, em seguida, usando NumberUtils :

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

Eu gostaria de lançar em outra proposta que funciona se um especificamente solicita números inteiros: basta usar muito tempo e usar Long.MIN_VALUE para casos de erro. Isso é semelhante à abordagem usada para caracteres no Reader, em que Reader.read () retorna um número inteiro no intervalo de um caractere ou -1 se o leitor estiver vazio.

Para Float e Double, NaN pode ser usado de maneira 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; } 

Você não deve usar exceções para validar seus valores .

Para um único caractere, existe uma solução simples:

 Character.isDigit() 

Para valores mais longos, é melhor usar alguns utilitários. NumberUtils fornecidos pelo Apache funcionariam perfeitamente aqui:

 NumberUtils.isNumber() 

Por favor, verifique https://commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/apache/commons/lang/math/NumberUtils.html

Você pode usar um object nulo como:

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

O resultado de main neste exemplo é:

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

Dessa forma, você pode sempre testar a conversão com falha, mas ainda trabalhar com os resultados como instâncias de número inteiro. Você também pode querer ajustar o número que o NULL representa (≠ 0).