Qual é a melhor maneira de verificar se a String representa um número inteiro em Java?

StackOverflow https://stackoverflow.com/questions/237159

  •  04-07-2019
  •  | 
  •  

Pergunta

Normalmente eu uso o seguinte idioma para verificar se a String pode ser convertido para um inteiro.

public boolean isInteger( String input ) {
    try {
        Integer.parseInt( input );
        return true;
    }
    catch( Exception e ) {
        return false;
    }
}

É apenas mim, ou isso parece um pouco hackish? O que é uma maneira melhor?


Veja a minha resposta (com valores de referência, com base na resposta anteriormente por CodingWithSpike ) para ver porque eu inverteu a minha posição e aceitou a resposta de Jonas Klemming para este problema. Acho que este código original será usado pela maioria das pessoas, porque é mais rápido para implementar e mais sustentável, mas é ordens de magnitude mais lenta quando os dados não inteiro é fornecido.

Foi útil?

Solução

Se você não está preocupado com problemas de estouro de potenciais esta função irá executar cerca de 20-30 vezes mais rápido do que usando Integer.parseInt().

public static boolean isInteger(String str) {
    if (str == null) {
        return false;
    }
    int length = str.length();
    if (length == 0) {
        return false;
    }
    int i = 0;
    if (str.charAt(0) == '-') {
        if (length == 1) {
            return false;
        }
        i = 1;
    }
    for (; i < length; i++) {
        char c = str.charAt(i);
        if (c < '0' || c > '9') {
            return false;
        }
    }
    return true;
}

Outras dicas

Você tem isso, mas você só deve pegar NumberFormatException.

Uma vez que não há possibilidade de que as pessoas ainda visitar aqui e vai ser tendenciosa contra Regex após os benchmarks ... Então eu vou te dar uma versão atualizada do benchmark, com uma versão compilada do Regex. Que se opôs aos benchmarks anteriores, esta solução Regex Um mostra realmente tem consistentemente bom desempenho.

Copiado de Bill o lagarto e atualizado com a versão compilada:

private final Pattern pattern = Pattern.compile("^-?\\d+$");

public void runTests() {
    String big_int = "1234567890";
    String non_int = "1234XY7890";

    long startTime = System.currentTimeMillis();
    for(int i = 0; i < 100000; i++)
            IsInt_ByException(big_int);
    long endTime = System.currentTimeMillis();
    System.out.print("ByException - integer data: ");
    System.out.println(endTime - startTime);

    startTime = System.currentTimeMillis();
    for(int i = 0; i < 100000; i++)
            IsInt_ByException(non_int);
    endTime = System.currentTimeMillis();
    System.out.print("ByException - non-integer data: ");
    System.out.println(endTime - startTime);

    startTime = System.currentTimeMillis();
    for(int i = 0; i < 100000; i++)
            IsInt_ByRegex(big_int);
    endTime = System.currentTimeMillis();
    System.out.print("\nByRegex - integer data: ");
    System.out.println(endTime - startTime);

    startTime = System.currentTimeMillis();
    for(int i = 0; i < 100000; i++)
            IsInt_ByRegex(non_int);
    endTime = System.currentTimeMillis();
    System.out.print("ByRegex - non-integer data: ");
    System.out.println(endTime - startTime);

    startTime = System.currentTimeMillis();
    for (int i = 0; i < 100000; i++)
            IsInt_ByCompiledRegex(big_int);
    endTime = System.currentTimeMillis();
    System.out.print("\nByCompiledRegex - integer data: ");
    System.out.println(endTime - startTime);

    startTime = System.currentTimeMillis();
    for (int i = 0; i < 100000; i++)
            IsInt_ByCompiledRegex(non_int);
    endTime = System.currentTimeMillis();
    System.out.print("ByCompiledRegex - non-integer data: ");
    System.out.println(endTime - startTime);


    startTime = System.currentTimeMillis();
    for(int i = 0; i < 100000; i++)
            IsInt_ByJonas(big_int);
    endTime = System.currentTimeMillis();
    System.out.print("\nByJonas - integer data: ");
    System.out.println(endTime - startTime);

    startTime = System.currentTimeMillis();
    for(int i = 0; i < 100000; i++)
            IsInt_ByJonas(non_int);
    endTime = System.currentTimeMillis();
    System.out.print("ByJonas - non-integer data: ");
    System.out.println(endTime - startTime);
}

private boolean IsInt_ByException(String str)
{
    try
    {
        Integer.parseInt(str);
        return true;
    }
    catch(NumberFormatException nfe)
    {
        return false;
    }
}

private boolean IsInt_ByRegex(String str)
{
    return str.matches("^-?\\d+$");
}

private boolean IsInt_ByCompiledRegex(String str) {
    return pattern.matcher(str).find();
}

public boolean IsInt_ByJonas(String str)
{
    if (str == null) {
            return false;
    }
    int length = str.length();
    if (length == 0) {
            return false;
    }
    int i = 0;
    if (str.charAt(0) == '-') {
            if (length == 1) {
                    return false;
            }
            i = 1;
    }
    for (; i < length; i++) {
            char c = str.charAt(i);
            if (c <= '/' || c >= ':') {
                    return false;
            }
    }
    return true;
}

Resultado:

ByException - integer data: 45
ByException - non-integer data: 465

ByRegex - integer data: 272
ByRegex - non-integer data: 131

ByCompiledRegex - integer data: 45
ByCompiledRegex - non-integer data: 26

ByJonas - integer data: 8
ByJonas - non-integer data: 2

Será que uma referência rápida. Exceções não são realmente que expensivve, a menos que você começar a estalar de volta vários métodos eo JVM tem que fazer um monte de trabalho para obter a pilha de execução no lugar. Quando ficar no mesmo método, eles não são artistas ruins.

 public void RunTests()
 {
     String str = "1234567890";

     long startTime = System.currentTimeMillis();
     for(int i = 0; i < 100000; i++)
         IsInt_ByException(str);
     long endTime = System.currentTimeMillis();
     System.out.print("ByException: ");
     System.out.println(endTime - startTime);

     startTime = System.currentTimeMillis();
     for(int i = 0; i < 100000; i++)
         IsInt_ByRegex(str);
     endTime = System.currentTimeMillis();
     System.out.print("ByRegex: ");
     System.out.println(endTime - startTime);

     startTime = System.currentTimeMillis();
     for(int i = 0; i < 100000; i++)
         IsInt_ByJonas(str);
     endTime = System.currentTimeMillis();
     System.out.print("ByJonas: ");
     System.out.println(endTime - startTime);
 }

 private boolean IsInt_ByException(String str)
 {
     try
     {
         Integer.parseInt(str);
         return true;
     }
     catch(NumberFormatException nfe)
     {
         return false;
     }
 }

 private boolean IsInt_ByRegex(String str)
 {
     return str.matches("^-?\\d+$");
 }

 public boolean IsInt_ByJonas(String str)
 {
     if (str == null) {
             return false;
     }
     int length = str.length();
     if (length == 0) {
             return false;
     }
     int i = 0;
     if (str.charAt(0) == '-') {
             if (length == 1) {
                     return false;
             }
             i = 1;
     }
     for (; i < length; i++) {
             char c = str.charAt(i);
             if (c <= '/' || c >= ':') {
                     return false;
             }
     }
     return true;
 }

Output:

ByException: 31

ByRegex: 453 (nota: re-compilar o padrão de cada vez)

ByJonas: 16

Eu concordo que a solução de Jonas K é o mais robusto também. Parece que ele ganha:)

org.apache.commons.lang.StringUtils.isNumeric 

embora lib padrão do Java realmente sente falta dessas funções utilitárias

Eu acho que o Apache Commons é um "must have" para cada Programador Java

Pena que não é portado para Java5 ainda

Isso depende, em parte, o que você quer dizer com "pode ??ser convertido para um inteiro".

Se você quer dizer "pode ??ser convertido em um int em Java", a resposta de Jonas é um bom começo, mas não chega a terminar o trabalho. Ele iria passar 999999999999999999999999999999 por exemplo. Gostaria de acrescentar a chamada try / catch normal a partir de sua própria pergunta no final do método.

As verificações caractere por caractere será eficiente rejeitam "não um inteiro em todos os casos", deixando "é um inteiro, mas Java não pode lidar com isso" casos de ser capturado por via de exceção mais lento. Você pode fazer isso pouco a mão também, mas seria um muito mais complicado.

Apenas um comentário sobre regexp. Cada exemplo fornecido aqui é errado !. Se você quiser usar regexp não se esqueça que compilar o padrão de ter um monte de tempo. Isto:

str.matches("^-?\\d+$")

e também isso:

Pattern.matches("-?\\d+", input);

faz com que compilação de padrão em cada chamada de método. Para utilizar corretamente seguir:

import java.util.regex.Pattern;

/**
 * @author Rastislav Komara
 */
public class NaturalNumberChecker {
    public static final Pattern PATTERN = Pattern.compile("^\\d+$");

    boolean isNaturalNumber(CharSequence input) {
        return input != null && PATTERN.matcher(input).matches();
    }
}

Eu copiou o código de resposta rally25rs e acrescentou alguns testes para dados não-inteiros. Os resultados são inegavelmente em favor do método postado por Jonas Klemming. Os resultados para o método de exceção que eu originalmente postadas são muito bons quando você tem dados inteiro, mas eles são o pior quando você não fizer isso, enquanto os resultados para a solução RegEx (que eu aposto que um monte de pessoas usam) foram consistentemente ruim. Consulte de Felipe resposta para um exemplo regex compilado, que é muito mais rápido.

public void runTests()
{
    String big_int = "1234567890";
    String non_int = "1234XY7890";

    long startTime = System.currentTimeMillis();
    for(int i = 0; i < 100000; i++)
        IsInt_ByException(big_int);
    long endTime = System.currentTimeMillis();
    System.out.print("ByException - integer data: ");
    System.out.println(endTime - startTime);

    startTime = System.currentTimeMillis();
    for(int i = 0; i < 100000; i++)
        IsInt_ByException(non_int);
    endTime = System.currentTimeMillis();
    System.out.print("ByException - non-integer data: ");
    System.out.println(endTime - startTime);

    startTime = System.currentTimeMillis();
    for(int i = 0; i < 100000; i++)
        IsInt_ByRegex(big_int);
    endTime = System.currentTimeMillis();
    System.out.print("\nByRegex - integer data: ");
    System.out.println(endTime - startTime);

    startTime = System.currentTimeMillis();
    for(int i = 0; i < 100000; i++)
        IsInt_ByRegex(non_int);
    endTime = System.currentTimeMillis();
    System.out.print("ByRegex - non-integer data: ");
    System.out.println(endTime - startTime);

    startTime = System.currentTimeMillis();
    for(int i = 0; i < 100000; i++)
        IsInt_ByJonas(big_int);
    endTime = System.currentTimeMillis();
    System.out.print("\nByJonas - integer data: ");
    System.out.println(endTime - startTime);

    startTime = System.currentTimeMillis();
    for(int i = 0; i < 100000; i++)
        IsInt_ByJonas(non_int);
    endTime = System.currentTimeMillis();
    System.out.print("ByJonas - non-integer data: ");
    System.out.println(endTime - startTime);
}

private boolean IsInt_ByException(String str)
{
    try
    {
        Integer.parseInt(str);
        return true;
    }
    catch(NumberFormatException nfe)
    {
        return false;
    }
}

private boolean IsInt_ByRegex(String str)
{
    return str.matches("^-?\\d+$");
}

public boolean IsInt_ByJonas(String str)
{
    if (str == null) {
            return false;
    }
    int length = str.length();
    if (length == 0) {
            return false;
    }
    int i = 0;
    if (str.charAt(0) == '-') {
            if (length == 1) {
                    return false;
            }
            i = 1;
    }
    for (; i < length; i++) {
            char c = str.charAt(i);
            if (c <= '/' || c >= ':') {
                    return false;
            }
    }
    return true;
}

Resultado:

ByException - integer data: 47
ByException - non-integer data: 547

ByRegex - integer data: 390
ByRegex - non-integer data: 313

ByJonas - integer data: 0
ByJonas - non-integer data: 16

Não é a versão goiaba:

import com.google.common.primitives.Ints;

Integer intValue = Ints.tryParse(stringValue);

Ele irá retornar nulo em vez de lançar uma exceção se ele falhar para analisar string.

Esta é mais curto, mas mais curto não é necessariamente melhor (e que não vai apanhar inteiro valores que estão fora de gama, como fora apontado em de danatel comentário ):

input.matches("^-?\\d+$");

Pessoalmente, desde a implementação é squirrelled afastado em um comprimento método auxiliar e trunfos de correção, gostaria apenas de ir com algo parecido com o que você tem (menos pegar a classe base Exception em vez de NumberFormatException).

Você pode usar o método partidas da classe string. O [0-9] representa todos os valores que podem ser, o + significa que deve ser, pelo menos, um carácter de comprimento, e os meios * Pode haver zero ou mais caracteres.

boolean isNumeric = yourString.matches("[0-9]+"); // 1 or more characters long, numbers only
boolean isNumeric = yourString.matches("[0-9]*"); // 0 or more characters long, numbers only

Esta é uma variação Java 8 de resposta Jonas Klemming:

public static boolean isInteger(String str) {
    return str != null && str.length() > 0 &&
         IntStream.range(0, str.length()).allMatch(i -> i == 0 && (str.charAt(i) == '-' || str.charAt(i) == '+')
                  || Character.isDigit(str.charAt(i)));
}

código de teste:

public static void main(String[] args) throws NoSuchAlgorithmException, UnsupportedEncodingException {
    Arrays.asList("1231231", "-1232312312", "+12313123131", "qwqe123123211", "2", "0000000001111", "", "123-", "++123",
            "123-23", null, "+-123").forEach(s -> {
        System.out.printf("%15s %s%n", s, isInteger(s));
    });
}

Os resultados do código de teste:

        1231231 true
    -1232312312 true
   +12313123131 true
  qwqe123123211 false
              2 true
  0000000001111 true
                false
           123- false
          ++123 false
         123-23 false
           null false
          +-123 false

Se a sua matriz String contém inteiros puros e Cordas, código abaixo deve funcionar. Você só tem que olhar primeiro caractere. por exemplo. [ "4", "44", "ABC", "77", "ligação"]

if (Character.isDigit(string.charAt(0))) {
    //Do something with int
}

Você também pode usar o Scanner classe e uso hasNextInt () -. e isso permite que você teste para outros tipos, também, como carros alegóricos, etc

Como sobre: ??

return Pattern.matches("-?\\d+", input);

Você apenas verificar NumberFormatException : -

 String value="123";
 try  
 {  
    int s=Integer.parseInt(any_int_val);
    // do something when integer values comes 
 }  
 catch(NumberFormatException nfe)  
 {  
          // do something when string values comes 
 }  

Você pode tentar apache utils

NumberUtils.isNumber( myText)

Veja o javadoc aqui

Você provavelmente precisará tomar o caso de uso em conta também:

Se a maior parte do tempo que você espera números para ser válida, em seguida, captura a exceção só é causando um desempenho sobrecarga ao tentar converter números inválidos. Considerando chamando algum método isInteger() e depois converter usando Integer.parseInt() irá sempre causa uma sobrecarga de desempenho para números válidos -. As cordas são analisados ??duas vezes, uma pelo cheque e uma vez pela conversão

Esta é uma modificação de Jonas 'código que verifica se a string está dentro do alcance para ser lançado em um inteiro.

public static boolean isInteger(String str) {
    if (str == null) {
        return false;
    }
    int length = str.length();
    int i = 0;

    // set the length and value for highest positive int or lowest negative int
    int maxlength = 10;
    String maxnum = String.valueOf(Integer.MAX_VALUE);
    if (str.charAt(0) == '-') { 
        maxlength = 11;
        i = 1;
        maxnum = String.valueOf(Integer.MIN_VALUE);
    }  

    // verify digit length does not exceed int range
    if (length > maxlength) { 
        return false; 
    }

    // verify that all characters are numbers
    if (maxlength == 11 && length == 1) {
        return false;
    }
    for (int num = i; num < length; num++) {
        char c = str.charAt(num);
        if (c < '0' || c > '9') {
            return false;
        }
    }

    // verify that number value is within int range
    if (length == maxlength) {
        for (; i < length; i++) {
            if (str.charAt(i) < maxnum.charAt(i)) {
                return true;
            }
            else if (str.charAt(i) > maxnum.charAt(i)) {
                return false;
            }
        }
    }
    return true;
}

Se você estiver usando a API do Android você pode usar:

TextUtils.isDigitsOnly(str);

Outra opção:

private boolean isNumber(String s) {
    boolean isNumber = true;
    for (char c : s.toCharArray()) {
        isNumber = isNumber && Character.isDigit(c);
    }
    return isNumber;
}

Se você quiser verificar se a cadeia representa um número inteiro que se encaixa em um tipo int, eu fiz uma pequena modificação para a resposta dos jonas, de modo que as cordas que representam números inteiros maiores que Integer.MAX_VALUE ou menores do que Integer.MIN_VALUE, agora irá retornar falso. Por exemplo: "3147483647" retornará falso porque 3147483647 é maior do que 2147483647, e da mesma forma, "-2147483649" irá também retornar falso porque -2147483649 é menor que -2147483648

.
public static boolean isInt(String s) {
  if(s == null) {
    return false;
  }
  s = s.trim(); //Don't get tricked by whitespaces.
  int len = s.length();
  if(len == 0) {
    return false;
  }
  //The bottom limit of an int is -2147483648 which is 11 chars long.
  //[note that the upper limit (2147483647) is only 10 chars long]
  //Thus any string with more than 11 chars, even if represents a valid integer, 
  //it won't fit in an int.
  if(len > 11) {
    return false;
  }
  char c = s.charAt(0);
  int i = 0;
  //I don't mind the plus sign, so "+13" will return true.
  if(c == '-' || c == '+') {
    //A single "+" or "-" is not a valid integer.
    if(len == 1) {
      return false;
    }
    i = 1;
  }
  //Check if all chars are digits
  for(; i < len; i++) {
    c = s.charAt(i);
    if(c < '0' || c > '9') {
      return false;
    }
  }
  //If we reached this point then we know for sure that the string has at
  //most 11 chars and that they're all digits (the first one might be a '+'
  // or '-' thought).
  //Now we just need to check, for 10 and 11 chars long strings, if the numbers
  //represented by the them don't surpass the limits.
  c = s.charAt(0);
  char l;
  String limit;
  if(len == 10 && c != '-' && c != '+') {
    limit = "2147483647";
    //Now we are going to compare each char of the string with the char in
    //the limit string that has the same index, so if the string is "ABC" and
    //the limit string is "DEF" then we are gonna compare A to D, B to E and so on.
    //c is the current string's char and l is the corresponding limit's char
    //Note that the loop only continues if c == l. Now imagine that our string
    //is "2150000000", 2 == 2 (next), 1 == 1 (next), 5 > 4 as you can see,
    //because 5 > 4 we can guarantee that the string will represent a bigger integer.
    //Similarly, if our string was "2139999999", when we find out that 3 < 4,
    //we can also guarantee that the integer represented will fit in an int.
    for(i = 0; i < len; i++) {
      c = s.charAt(i);
      l = limit.charAt(i);
      if(c > l) {
        return false;
      }
      if(c < l) {
        return true;
      }
    }
  }
  c = s.charAt(0);
  if(len == 11) {
    //If the first char is neither '+' nor '-' then 11 digits represent a 
    //bigger integer than 2147483647 (10 digits).
    if(c != '+' && c != '-') {
      return false;
    }
    limit = (c == '-') ? "-2147483648" : "+2147483647";
    //Here we're applying the same logic that we applied in the previous case
    //ignoring the first char.
    for(i = 1; i < len; i++) {
      c = s.charAt(i);
      l = limit.charAt(i);
      if(c > l) {
        return false;
      }
      if(c < l) {
        return true;
      }
    }
  }
  //The string passed all tests, so it must represent a number that fits
  //in an int...
  return true;
}
is_number = true;
try {
  Integer.parseInt(mystr)
} catch (NumberFormatException  e) {
  is_number = false;
}

O que você fez obras, mas você provavelmente não deve sempre verificar se forma. exceções jogando deve ser reservada para situações "excepcionais" (talvez que cabe no seu caso, embora), e são muito caro em termos de desempenho.

Number number;
try {
    number = NumberFormat.getInstance().parse("123");
} catch (ParseException e) {
    //not a number - do recovery.
    e.printStackTrace();
}
//use number

Isso funcionaria apenas para números inteiros positivos.

public static boolean isInt(String str) {
    if (str != null && str.length() != 0) {
        for (int i = 0; i < str.length(); i++) {
            if (!Character.isDigit(str.charAt(i))) return false;
        }
    }
    return true;        
}

Isso funciona para mim. Simplesmente para identificar se uma string é um primitivo ou um número.

private boolean isPrimitive(String value){
        boolean status=true;
        if(value.length()<1)
            return false;
        for(int i = 0;i<value.length();i++){
            char c=value.charAt(i);
            if(Character.isDigit(c) || c=='.'){

            }else{
                status=false;
                break;
            }
        }
        return status;
    }

Para verificar se todos os caracteres int, você pode simplesmente usar uma dupla negativa.

Se (! searchString.matches ( "[^ 0-9] + $")) ...

[^ 0-9] + $ verifica se existem quaisquer caracteres que não são inteiro, então o teste falhar se é verdade. Não apenas que e você terá verdadeira em caso de sucesso.

Encontre esta may útil:

public static boolean isInteger(String self) {
    try {
        Integer.valueOf(self.trim());
        return true;
    } catch (NumberFormatException nfe) {
        return false;
    }
}

Eu acredito que há risco zero correndo em uma exceção, porque como você pode ver abaixo você sempre int segurança análise para String e não o contrário.

Assim:

  1. Você verificação se cada ranhura da personagem em seus jogos de cordas pelo menos um dos caracteres { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"} .

    if(aString.substring(j, j+1).equals(String.valueOf(i)))
    
  2. Você sum todas as vezes que você encontrou nas ranhuras do acima caracteres.

    digits++;
    
  3. E, finalmente, você verificação se as vezes que você encontrou inteiros como caracteres iguais, com o comprimento da corda dada.

    if(digits == aString.length())
    

E, na prática, temos:

    String aString = "1234224245";
    int digits = 0;//count how many digits you encountered
    for(int j=0;j<aString.length();j++){
        for(int i=0;i<=9;i++){
            if(aString.substring(j, j+1).equals(String.valueOf(i)))
                    digits++;
        }
    }
    if(digits == aString.length()){
        System.out.println("It's an integer!!");
        }
    else{
        System.out.println("It's not an integer!!");
    }

    String anotherString = "1234f22a4245";
    int anotherDigits = 0;//count how many digits you encountered
    for(int j=0;j<anotherString.length();j++){
        for(int i=0;i<=9;i++){
            if(anotherString.substring(j, j+1).equals(String.valueOf(i)))
                    anotherDigits++;
        }
    }
    if(anotherDigits == anotherString.length()){
        System.out.println("It's an integer!!");
        }
    else{
        System.out.println("It's not an integer!!");
    }

E os resultados são:

É um inteiro !!

Não é um inteiro !!

Da mesma forma, você pode validar se um String é um float ou um double mas nesses casos você tem que encontro único. (dot) na cadeia e de verificação claro que se digits == (aString.length()-1)

Mais uma vez, não há risco zero correr em uma exceção de análise aqui, mas se você está pensando em analisar uma string que é sabido que contém um número (digamos int tipo de dados) você deve primeiro verificar se ele se encaixa no tipo de dados. Caso contrário, você deve lançá-lo.

Espero ter ajudado

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top