Каков наилучший способ проверить, является ли String целое число в Java?

Обычно я использую следующую идиому, чтобы проверить, может ли String быть преобразовано в целое число.

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

Это только я, или это кажется немного хаки? Какой лучший способ?


См. мой ответ (с помощью тестов, основанных на более раннем ответе CodingWithSpike), чтобы увидеть почему я отменил свою позицию и принял ответ Джонаса Клемминга на эту проблему. Я думаю, что этот оригинальный код будет использоваться большинством людей, потому что он быстрее реализуется и более ремонтируемый, но на несколько порядков медленнее, когда предоставляются нецелые данные.

Ответ 1

Если вы не связаны с потенциальными проблемами переполнения, эта функция будет работать примерно в 20-30 раз быстрее, чем при использовании 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;
}

Ответ 2

У вас есть это, но вы должны поймать NumberFormatException.

Ответ 3

Был быстрый тест. Исключения на самом деле не являются дорогостоящими, если вы не начнете выскакивать несколько методов, и JVM должна выполнить большую работу, чтобы получить исполняемый стек на месте. Когда вы остаетесь в том же методе, они не плохие исполнители.

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

Вывод:

ByException: 31

ByRegex: 453 (обратите внимание: повторная компиляция шаблона каждый раз)

ByJonas: 16

Я согласен с тем, что решение Jonas K является самым надежным. Похоже, он побеждает:)

Ответ 4

Поскольку существует вероятность того, что люди все еще будут посещать здесь и будут предвзяты против Regex после тестов... Итак, я дам обновленную версию теста со скомпилированной версией Regex. Что противоположно предыдущим критериям, это показывает, что решение Regex действительно имеет хорошую производительность.

Скопировано из Билла Ящерицы и обновлено с помощью скомпилированной версии:

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

Результаты:

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

Ответ 5

org.apache.commons.lang.StringUtils.isNumeric 

хотя Java standard lib действительно пропускает такие служебные функции

Я думаю, что Apache Commons является "обязательным" для каждого Java-программиста

слишком плохо, что он еще не переносится на Java5

Ответ 6

Отчасти это зависит от того, что вы подразумеваете под "можно преобразовать в целое число".

Если вы имеете в виду, что "может быть преобразован в int в Java", то ответ от Jonas - хорошее начало, но не совсем завершает работу. Например, он пройдет 999999999999999999999999999999. Я бы добавил обычный вызов try/catch из вашего собственного вопроса в конце метода.

Проверки по каждому символу будут эффективно отклонять случаи "не целого числа", оставив при этом "это целое, но Java не может справиться" с случаями, которые будут обнаружены медленным маршрутом исключения. Вы тоже могли бы сделать это вручную, но это было бы намного сложнее.

Ответ 7

Только один комментарий о regexp. Каждый пример, приведенный здесь, неверен!. Если вы хотите использовать regexp, не забывайте, что компиляция шаблона занимает много времени. Это:

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

а также это:

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

вызывает компиляцию шаблона в каждом вызове метода. Правильно использовать его:

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

Ответ 8

Я скопировал код из ответа rally25rs и добавил несколько тестов для нецелых данных. Результаты неоспоримо в пользу метода, публикуемую Йонас Klemming. Результаты для метода Exception, которые я изначально опубликовал, довольно хороши, когда у вас есть целочисленные данные, но они самые худшие, когда вы этого не делаете, в то время как результаты для решения RegEx (что я поставил, многие люди используют) были последовательно плохими. См. Ответ Felipe для скомпилированного примера регулярного выражения, который намного быстрее.

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

Результаты:

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

Ответ 9

Существует версия guava:

import com.google.common.primitives.Ints;

Integer intValue = Ints.tryParse(stringValue);

Он будет возвращать значение null вместо того, чтобы бросать исключение, если ему не удается проанализировать строку.

Ответ 10

Это короче, но короче не обязательно лучше (и он не поймает целочисленные значения, которые находятся вне диапазона, как указано в комментарии danatel)

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

Лично, поскольку реализация выполняется с помощью вспомогательного метода и длины кодов правильности, я бы просто пошел с чем-то вроде того, что у вас есть (минус ловить базовый класс Exception, а не NumberFormatException).

Ответ 11

Вы можете использовать метод совпадений класса string. [0-9] представляет все значения, которые он может быть, символ + означает, что он должен содержать по крайней мере один символ, а символ * означает, что он может содержать ноль или более символов.

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

Ответ 12

Это вариация ответа Джонаса Клемминга на Java 8:

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

Тестовый код:

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

Результаты тестового кода:

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

Ответ 13

Вы также можете использовать класс Scanner и использовать hasNextInt() - и это позволяет тестировать и другие типы, такие как float и т.д.

Ответ 14

Если ваш массив String содержит чистые целые числа и строки, код ниже должен работать. Вам нужно только взглянуть на первого персонажа. например [ "4", "44", "ABC", "77", "связь" ]

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

Ответ 15

Как насчет:

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

Ответ 16

Вы просто проверяете 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 
 }  

Ответ 18

Вероятно, вам нужно также воспользоваться прецедентом:

Если в большинстве случаев вы ожидаете, что числа будут действительными, то перехват исключения приведет к накладным расходам на производительность при попытке конвертировать недопустимые числа. В то время как вызов некоторого метода isInteger(), а затем преобразование с использованием Integer.parseInt() всегда будет приводить к накладной производительности для действительных чисел - строки анализируются дважды, один раз проверкой и один раз путем преобразования.

Ответ 19

Это модификация кода Jonas ", который проверяет, находится ли строка в пределах диапазона, который будет передан в целое число.

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

Ответ 20

Если вы используете Android API, вы можете использовать:

TextUtils.isDigitsOnly(str);

Ответ 21

Другая опция:

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

Ответ 22

Если вы хотите проверить, соответствует ли строка целому числу, которое соответствует типу int, я сделал небольшую модификацию ответа jonas, так что строки, представляющие целые числа больше Integer.MAX_VALUE или меньше Integer.MIN_VALUE, теперь вернет false. Например: "3147483647" вернет false, потому что 3147483647 больше, чем 2147483647, а также "-2147483649" также вернет false, потому что -2147483649 меньше, чем -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 char and l is the corresponding limit 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;
}

Ответ 23

is_number = true;
try {
  Integer.parseInt(mystr)
} catch (NumberFormatException  e) {
  is_number = false;
}

Ответ 24

То, что вы делали, работает, но вы, вероятно, не всегда должны так проверять. Выбрасывание исключений должно быть зарезервировано для "исключительных" ситуаций (возможно, это подходит в вашем случае), и они очень дорогостоящие с точки зрения производительности.

Ответ 25

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

Ответ 26

Это будет работать только для целых положительных чисел.

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

Ответ 27

Это работает для меня. Просто определить, является ли String примитивным или числом.

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

Ответ 28

Чтобы проверить все символы int, вы можете просто использовать двойной отрицательный.

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

[^ 0-9] + $проверяет, есть ли какие-либо символы, которые не являются целыми, поэтому тест терпит неудачу, если он истинен. Просто НЕ, и вы вернетесь к успеху.

Ответ 29

Я считаю, что в исключении возникает нулевой риск, потому что, как вы можете видеть ниже, вы всегда безопасно разбираете int до String, а не наоборот.

Итак:

  • Вы проверяете, если каждый слот символа в вашей строке соответствует хотя бы один из символов { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" }.

    if(aString.substring(j, j+1).equals(String.valueOf(i)))
    
  • Вы sum все время, которое вы встретили в слотах выше символы.

    digits++;
    
  • И, наконец, вы проверяете, если время, когда вы столкнулись с целыми числами как символы равны длине данной строки.

    if(digits == aString.length())
    

И на практике мы имеем:

    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 an integer!!");
        }
    else{
        System.out.println("It 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 an integer!!");
        }
    else{
        System.out.println("It not an integer!!");
    }

И результаты:

Это целое число!

Это не целое число!

Аналогично, вы можете проверить, является ли String float или double, но в этих случаях вам нужно встретить только один. (точка) в строке и, конечно же, проверьте, если digits == (aString.length()-1)

Опять же, здесь отсутствует риск, связанный с исключением синтаксического анализа, но если вы планируете разбор строки, которая, как известно, содержит число (например, тип int), вы должны сначала проверить, он подходит для типа данных. В противном случае вы должны бросить его.

Надеюсь, я помог

Ответ 30

Найти это может быть полезно:

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