What's the best way to check if a String represents an integer in Java?
Asked Answered
R

40

252

I normally use the following idiom to check if a String can be converted to an integer.

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

Is it just me, or does this seem a bit hackish? What's a better way?


See my answer (with benchmarks, based on the earlier answer by CodingWithSpike) to see why I've reversed my position and accepted Jonas Klemming's answer to this problem. I think this original code will be used by most people because it's quicker to implement, and more maintainable, but it's orders of magnitude slower when non-integer data is provided.

Raid answered 25/10, 2008 at 22:58 Comment(1)
Does this answer your question? How to check if a String is numeric in JavaHerron
V
194

If you are not concerned with potential overflow problems this function will perform about 20-30 times faster than using 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;
}
Vitrics answered 25/10, 2008 at 23:32 Comment(15)
(c <= '/' || c >= ':') is a bit strange looking. I would have used (c < '0' || c > '9')... are the <= and >= operators faster in Java?Traherne
Why not use regex? Isn't return str.matches("^-?\\d+$") identical to code above.Gregale
I would use this method or the original method from the question before regex. This for performance, the original method for speed of implementation and sheer maintainability. The regex solution has nothing going for it.Raid
I am worried about overflow, but this method can be adapted for BigInts and still be way faster than other methods. In case anyone is wondering why I'm putting so much effort into such a simple problem, I'm creating a library to aid in solving Project Euler problems.Raid
If you are concerned whether you can actually parse the string into an int or long you would also need to check if the integer the string represents actually fits into those data types.Vitrics
Note that this function is much faster but in the end you don't have an Integer! If you are going to use the result to actually convert the string, the the performance gain is not as important if the situation is "exceptional".Rameau
Wouldn't this return True if str == "a123"?Alcala
How do you check for strings that start with a '0'?Dorindadorine
@Bill: Not quite true that the regex solution has nothing going for it. It uses the class \d, which avoids dependencies both on numeral characters (e.g. '0' and '9' vs. Persian numerals) and on ordering thereof (the < > comparison). These dependencies are actually fragile, as you'll see once your integers arrive looking like ۵۷۱۰. The regex might actually work out-of-the-box, assuming the locale is set correctly.Acceptable
The first lines to check whether "str" is null or empty could be replaced with TextUtils.isEmpty(str). TextUtils is part of the SDK and does essentially the same thing.Mog
Depends. Does "2.00" = 2? For computers, normally no. For mathematicians and humans who have had high school math, yes. Therefore, the above answer is weak. What about "2."? or ".00"? See below for a first cut on how to handle situations like that.Lock
Just as like with any filtering method, if you have a small amount of false positives, and the amount of positives itself is also much smaller than the amount of negative answers, you can always stage a more comprehensive check after the quick check. (note - positives = answers with a boolean 'true' outcome; negatives = answers with a boolean 'false' outcome).Tenfold
@Lock What about scientific notation? What about octal or hexadecimal numbers? What about expressions like 2 + 2, which can be simplified to 4? And so on. This answer is perfectly fine considering what it solves (simple integer values without accounting for overflow).Jarrett
when input is one single operator like "*", the function will also return true...Affray
Why check length == 0 and length == 1 separately? Wouldn't length <= 1 make this run even faster / use less code?Suite
V
68

You have it, but you should only catch NumberFormatException.

Victoriavictorian answered 25/10, 2008 at 23:3 Comment(6)
Yeah, it's considered bad form to catch more exceptions than you need.Inducement
You're right. NFE is the only one that can be thrown, but it's still a bad habit to get into.Raid
I think a NPE can be thrown if input is null, so your method should probably handle that explicitly, whichever way you want to.Eure
@Dov: You're right NPE and NFE should both be explicitly caught.Raid
In my opinion, this sequence of comments actually makes a good case for catching java.lang.Exception (or Throwable), demonstrating how it is just too easy to miss one.Reprove
Downvote because catching exceptions is the opposite to code for performance :PMelvamelvena
V
44

Did a quick benchmark. Exceptions aren't actually that expensivve, unless you start popping back multiple methods and the JVM has to do a lot of work to get the execution stack in place. When staying in the same method, they aren't bad performers.

 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 (note: re-compiling the pattern every time)

ByJonas: 16

I do agree that Jonas K's solution is the most robust too. Looks like he wins :)

Verbatim answered 26/10, 2008 at 1:18 Comment(6)
Great idea to benchmark all three. To be fair to the Regex and Jonas methods, you should test with non-integer strings, since that's where the Integer.parseInt method is going to really slow down.Raid
Sorry but this regex test is not good. (1) You don't need to make regex engine check for ^ and $ second time since in matches entire string must match regex, (2) str.matches each time will have to create its own Pattern which is expensive. For performance reasons we should create such Pattern only once outside this method and use it inside. (3) We can also create only one Matcher object and use its reset(CharSequence) to pass user data and return its matches() result.Connett
So something like private final Matcher m = Pattern.compile("-?\\d+").matcher(""); private boolean byRegex(String str) { return m.reset(str).matches(); } should have better performance.Connett
@Connett Integer.valueOf(" 1") and Integer.valueOf("1 ") both throw exception so checking for ^ and $ seem reasonable.Rameau
@Rameau Yes, but it is not required since matches is adding ^ and $ implicitly. Take a look at result of " 123".matches("\\d+") and "123".matches("\\d+"). You will see false and true. false will be returned because string starts with space which prevents it from being entirely matched by regex.Connett
"Exceptions aren't actually that expensive" - that's only because you test value that is Integer, so exception in never thrown. Test this on not numeric value, and version with exception will be about two times slower than regex one.Clifford
O
41
org.apache.commons.lang.StringUtils.isNumeric 

though Java's standard lib really misses such utility functions

I think that Apache Commons is a "must have" for every Java programmer

too bad it isn't ported to Java5 yet

Ordain answered 25/10, 2008 at 22:59 Comment(2)
The only problem with this is overflow :S I still give you +1 for mentioning commons-lang :)Loon
The other problem is negative numbers, but I also +1, since in my view this approach comes closest to a good solution.Weber
F
37

Since there's possibility that people still visit here and will be biased against Regex after the benchmarks... So i'm gonna give an updated version of the benchmark, with a compiled version of the Regex. Which opposed to the previous benchmarks, this one shows Regex solution actually has consistently good performance.

Copied from Bill the Lizard and updated with compiled version:

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

Results:

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
Flitting answered 25/10, 2008 at 22:59 Comment(5)
The ByCompiledRegex time needs to include compiling the regex in its time measurement.Manna
@MartinCarney I modified it and benchmarked pattern compilation. Obviously my CPU/JIT is faster, but if I interpolate it back, the compilation time is 336.Threnode
to be clear, that 336 (ms) is what happens when the pattern compilation is done 100k times, just like all the other lines. With the implication that it's only done once, its time is basically zero.Threnode
Thanks for setting the record straight on the compiled regex times.Acceptable
Maybe "^[+-]?\\d+$" would be even better.Ascension
I
24

It partly depend on what you mean by "can be converted to an integer".

If you mean "can be converted into an int in Java" then the answer from Jonas is a good start, but doesn't quite finish the job. It would pass 999999999999999999999999999999 for example. I would add the normal try/catch call from your own question at the end of the method.

The character-by-character checks will efficiently reject "not an integer at all" cases, leaving "it's an integer but Java can't handle it" cases to be caught by the slower exception route. You could do this bit by hand too, but it would be a lot more complicated.

Inhumane answered 26/10, 2008 at 7:26 Comment(0)
S
20

Just one comment about regexp. Every example provided here is wrong!. If you want to use regexp don't forget that compiling the pattern take a lot of time. This:

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

and also this:

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

causes compile of pattern in every method call. To used it correctly follow:

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();
    }
}
Songstress answered 26/10, 2008 at 11:27 Comment(1)
You can squeeze out a little more performance by creating the Matcher ahead of time, too, and using its reset() method to apply it to the input.Ocana
B
16

There is guava version:

import com.google.common.primitives.Ints;

Integer intValue = Ints.tryParse(stringValue);

It will return null instead of throwing an exception if it fails to parse string.

Buckley answered 7/1, 2016 at 9:14 Comment(2)
Best answer IMHO. Use well tested libraries instead of rolling up your own solution. (Also see the discussion here.)Busse
return Ints.tryParse(stringValue) != null; for the equivalent boolean result as OP's isInteger method.Shlomo
R
12

I copied the code from rally25rs answer and added some tests for non-integer data. The results are undeniably in favor of the method posted by Jonas Klemming. The results for the Exception method that I originally posted are pretty good when you have integer data, but they're the worst when you don't, while the results for the RegEx solution (that I'll bet a lot of people use) were consistently bad. See Felipe's answer for a compiled regex example, which is much faster.

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

Results:

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
Raid answered 26/10, 2008 at 13:13 Comment(0)
O
6

This is shorter, but shorter isn't necessarily better (and it won't catch integer values which are out of range, as pointed out in danatel's comment):

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

Personally, since the implementation is squirrelled away in a helper method and correctness trumps length, I would just go with something like what you have (minus catching the base Exception class rather than NumberFormatException).

Obsequent answered 25/10, 2008 at 23:4 Comment(1)
And maybe \\d{1,10} is, although not perfect, better than \\d+ for catching Java IntegersGregale
L
6

You can use the matches method of the string class. The [0-9] represents all the values it can be, the + means it must be at least one character long, and the * means it can be zero or more characters long.

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
Leatherback answered 13/12, 2012 at 21:41 Comment(1)
Nb this doest not match "+10" or "-10"), which would normally be included as valid integersBrachylogy
P
4

How about:

return Pattern.matches("-?\\d+", input);
Pram answered 25/10, 2008 at 23:3 Comment(4)
What about the integer 9999999999999999999999999999999999 ?Shinny
Don't forget to check for the negative sign.Tarratarradiddle
don't you need to anchor the begining and end of the regex, so you won't pass "aaa-1999zzz"?Ganesha
Tim, when you call one of the matches() methods (String, Pattern and Matcher each have one), the regex has to match the whole input, making anchors redundant. To find a match as defined by most other regex flavors, you have to use Matcher#find().Ocana
R
4

This is a Java 8 variation of Jonas Klemming answer:

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

Test code:

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

Results of the test code:

        1231231 true
    -1232312312 true
   +12313123131 true
  qwqe123123211 false
              2 true
  0000000001111 true
                false
           123- false
          ++123 false
         123-23 false
           null false
          +-123 false
Redstone answered 23/3, 2017 at 19:54 Comment(0)
S
3

You can also use the Scanner class, and use hasNextInt() - and this allows you to test for other types, too, like floats, etc.

Sherwood answered 26/10, 2008 at 5:27 Comment(0)
U
3

You just check 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 
 }  
Urata answered 26/7, 2013 at 6:12 Comment(0)
F
3

You may try apache utils

NumberUtils.isCreatable(myText)

See the javadoc here

Franks answered 25/2, 2014 at 11:15 Comment(1)
Seems that this method is deprecated in the latest release link). Apparently you should use isCreateable(String) instead.Jarrett
R
3

If your String array contains pure Integers and Strings, code below should work. You only have to look at first character. e.g. ["4","44","abc","77","bond"]

if (Character.isDigit(string.charAt(0))) {
    //Do something with int
}
Roselane answered 18/3, 2014 at 2:19 Comment(0)
M
3

Another option:

private boolean isNumber(String s) {
    boolean isNumber = true;
    for (char c : s.toCharArray()) {
        isNumber = isNumber && Character.isDigit(c);
    }
    return isNumber;
}
Minerva answered 22/4, 2016 at 0:8 Comment(0)
A
3

If you want to check if the string represents an integer that fits in an int type, I did a little modification to the jonas' answer, so that strings that represent integers bigger than Integer.MAX_VALUE or smaller than Integer.MIN_VALUE, will now return false. For example: "3147483647" will return false because 3147483647 is bigger than 2147483647, and likewise, "-2147483649" will also return false because -2147483649 is smaller than -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;
}
Arron answered 25/8, 2017 at 1:59 Comment(3)
can you please edit your answer and explain how it improves the previous answer you mentioned ?Affectionate
Thanks for the great answer. But "123 " i.e., 123 along with space is considered as the valid integer.Urgent
@SaikrishnaRadarapu They use trim() so that’s clearly an intentional design choice.Jarrett
P
2

several answers here saying to try parsing to an integer and catching the NumberFormatException but you should not do this.

That way would create exception object and generates a stack trace each time you called it and it was not an integer.

A better way with Java 8 would be to use a stream:

boolean isInteger = returnValue.chars().allMatch(Character::isDigit);
Perfection answered 5/11, 2020 at 9:16 Comment(0)
G
1

You probably need to take the use case in account too:

If most of the time you expect numbers to be valid, then catching the exception is only causing a performance overhead when attempting to convert invalid numbers. Whereas calling some isInteger() method and then convert using Integer.parseInt() will always cause a performance overhead for valid numbers - the strings are parsed twice, once by the check and once by the conversion.

Goldbrick answered 25/10, 2008 at 22:59 Comment(0)
N
1

This is a modification of Jonas' code that checks if the string is within range to be cast into an integer.

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;
}
Neale answered 31/7, 2014 at 22:12 Comment(2)
looks good, but the last for-loop needs to have i reset to zero (or 1 if a negative number) because the loop that checks whether each digit is a number will result in i being the string length, therefore the last for-loop will never run. I would also use the Java constants Integer.MAX_VALUE and Integer.MIN_VALUE instead of the magic numbers.Song
@TimtheEnchanter Thank you for the suggestions, I completely overlooked them. In my edit to incorporate them I used a new variable in the first for loop to avoid the extra if statement.Neale
S
1

I believe there's zero risk running into an exception, because as you can see below you always safely parse int to String and not the other way around.

So:

  1. You check if every slot of character in your string matches at least one of the characters {"0","1","2","3","4","5","6","7","8","9"}.

    if(aString.substring(j, j+1).equals(String.valueOf(i)))
    
  2. You sum all the times that you encountered in the slots the above characters.

    digits++;
    
  3. And finally you check if the times that you encountered integers as characters equals with the length of the given string.

    if(digits == aString.length())
    

And in practice we have:

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

And the results are:

It's an integer!!

It's not an integer!!

Similarly, you can validate if a String is a float or a double but in those cases you have to encounter only one . (dot) in the String and of course check if digits == (aString.length()-1)

Again, there's zero risk running into a parsing exception here, but if you plan on parsing a string that it is known that contains a number (let's say int data type) you must first check if it fits in the data type. Otherwise you must cast it.

I hope I helped

Sentimentalize answered 22/4, 2015 at 23:16 Comment(0)
F
1

If you are using the Android API you can use:

TextUtils.isDigitsOnly(str);
Fleer answered 8/7, 2015 at 12:32 Comment(0)
T
0

This would work only for positive integers.

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;        
}
Tackle answered 25/10, 2008 at 22:59 Comment(1)
Welcome to stackoverflow. Before resurrecting an old thread be sure to read the previous responses and comments. This method (and possible disadvantages) were actually discussed already.Limonite
D
0

What you did works, but you probably shouldn't always check that way. Throwing exceptions should be reserved for "exceptional" situations (maybe that fits in your case, though), and are very costly in terms of performance.

Decarbonate answered 25/10, 2008 at 23:12 Comment(1)
They're only costly if they get thrown.Raid
S
0

This works for me. Simply to identify whether a String is a primitive or a number.

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;
    }
Stern answered 19/12, 2014 at 8:58 Comment(0)
H
0

To check for all int chars, you can simply use a double negative.

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

[^0-9]+$ checks to see if there are any characters that are not integer, so the test fails if it's true. Just NOT that and you get true on success.

Hoppe answered 29/3, 2015 at 13:39 Comment(3)
No. You clearly haven't tested this. This only returns true if there's a digit somewhere in the string, not if the string is only digits. The matches method matches against the entire string, not just a portion of it.Palish
You don't get the double negative part.Hoppe
Well, I don't NOT get the double negative. This simply doesn't work. If you have a mixture of digits and letters, this goes into the if block. It shouldn't.Palish
A
0

I have seen a lot of answers here, but most of them are able to determine whether the String is numeric, but they fail checking whether the number is in Integer range...

Therefore I purpose something like this:

public static boolean isInteger(String str) {
    if (str == null || str.isEmpty()) {
        return false;
    }
    try {
        long value = Long.valueOf(str);
        return value >= -2147483648 && value <= 2147483647;
    } catch (Exception ex) {
        return false;
    }
}
Asher answered 1/11, 2016 at 10:54 Comment(3)
Good point, handled by com.google.common.primitives.Ints.tryParse(String, int) suggested in the Guava answer.Leilanileininger
But the string value has a chance to go beyond the long limit too. How can we assume that it is within the long range. For example string can hold this value too 9,223,372,036,854,775,809 but long cannot in which case we get an NumberFormatException.Jaimiejain
The method should check, it the value represented by the String is within the Integer range. If you supply the method with an argument, which is even larger than Long, then it certainly isn't an Integer and the method should return "false". Which it does, since the conversion raises an error and the catch clause then provides "false".Asher
L
0

When explanations are more important than performance

I noticed many discussions centering how efficient certain solutions are, but none on why an string is not an integer. Also, everyone seemed to assume that the number "2.00" is not equal to "2". Mathematically and humanly speaking, they are equal (even though computer science says that they are not, and for good reason). This is why the "Integer.parseInt" solutions above are weak (depending on your requirements).

At any rate, to make software smarter and more human-friendly, we need to create software that thinks like we do and explains why something failed. In this case:

public static boolean isIntegerFromDecimalString(String possibleInteger) {
possibleInteger = possibleInteger.trim();
try {
    // Integer parsing works great for "regular" integers like 42 or 13.
    int num = Integer.parseInt(possibleInteger);
    System.out.println("The possibleInteger="+possibleInteger+" is a pure integer.");
    return true;
} catch (NumberFormatException e) {
    if (possibleInteger.equals(".")) {
        System.out.println("The possibleInteger=" + possibleInteger + " is NOT an integer because it is only a decimal point.");
        return false;
    } else if (possibleInteger.startsWith(".") && possibleInteger.matches("\\.[0-9]*")) {
        if (possibleInteger.matches("\\.[0]*")) {
            System.out.println("The possibleInteger=" + possibleInteger + " is an integer because it starts with a decimal point and afterwards is all zeros.");
            return true;
        } else {
            System.out.println("The possibleInteger=" + possibleInteger + " is NOT an integer because it starts with a decimal point and afterwards is not all zeros.");
            return false;
        }
    } else if (possibleInteger.endsWith(".")  && possibleInteger.matches("[0-9]*\\.")) {
        System.out.println("The possibleInteger="+possibleInteger+" is an impure integer (ends with decimal point).");
        return true;
    } else if (possibleInteger.contains(".")) {
        String[] partsOfPossibleInteger = possibleInteger.split("\\.");
        if (partsOfPossibleInteger.length == 2) {
            //System.out.println("The possibleInteger=" + possibleInteger + " is split into '" + partsOfPossibleInteger[0] + "' and '" + partsOfPossibleInteger[1] + "'.");
            if (partsOfPossibleInteger[0].matches("[0-9]*")) {
                if (partsOfPossibleInteger[1].matches("[0]*")) {
                    System.out.println("The possibleInteger="+possibleInteger+" is an impure integer (ends with all zeros after the decimal point).");
                    return true;
                } else if (partsOfPossibleInteger[1].matches("[0-9]*")) {
                    System.out.println("The possibleInteger=" + possibleInteger + " is NOT an integer because it the numbers after the decimal point (" + 
                                partsOfPossibleInteger[1] + ") are not all zeros.");
                    return false;
                } else {
                    System.out.println("The possibleInteger=" + possibleInteger + " is NOT an integer because it the 'numbers' after the decimal point (" + 
                            partsOfPossibleInteger[1] + ") are not all numeric digits.");
                    return false;
                }
            } else {
                System.out.println("The possibleInteger=" + possibleInteger + " is NOT an integer because it the 'number' before the decimal point (" + 
                        partsOfPossibleInteger[0] + ") is not a number.");
                return false;
            }
        } else {
            System.out.println("The possibleInteger="+possibleInteger+" is NOT an integer because it has a strange number of decimal-period separated parts (" +
                    partsOfPossibleInteger.length + ").");
            return false;
        }
    } // else
    System.out.println("The possibleInteger='"+possibleInteger+"' is NOT an integer, even though it has no decimal point.");
    return false;
}
}

Test code:

String[] testData = {"0", "0.", "0.0", ".000", "2", "2.", "2.0", "2.0000", "3.14159", ".0001", ".", "$4.0", "3E24", "6.0221409e+23"};
int i = 0;
for (String possibleInteger : testData ) {
    System.out.println("");
    System.out.println(i + ". possibleInteger='" + possibleInteger +"' isIntegerFromDecimalString=" + isIntegerFromDecimalString(possibleInteger));
    i++;
}
Lock answered 30/6, 2018 at 17:2 Comment(2)
I think your explanation sheds light on situations that people would honestly not think of and would allow for a lot more robust code. However, you assume we use a period (.) for our delimiter. It does not cover readability of the input such as: the thousand separator, accounting parentheses, a different base, or that we use Arabic numbers. There is also no reason to throw an exception in this method as we know every state this string should be in given it's immutable state and we are going to be good programmers and modify the reference - further reading wiki.c2.com/?ExceptionPatternsTeddi
David - you are absolutely correct; especially about the comma thousand separator (which is important for readability). For a truly general solution, we would need to take into account all the assumptions--though I'm fairly certain that not too many people use non-Arabic numbers. :-)Lock
J
0

I do not like method with regex, because regex can not check ranges (Integer.MIN_VALUE, Integer.MAX_VALUE).

If you expect int value in most cases, and not int is something uncommon, then I suggest version with Integer.valueOf or Integer.parseInt with NumberFormatException catching. Advantage of this approach - your code has good readability:

public static boolean isInt(String s) {
  try {
    Integer.parseInt(s);
    return true;
  } catch (NumberFormatException nfe) {
    return false;
  }
}

If you need to check if String is integer, and care about perfomance then the best way will be to use java jdk implementation of Integer.parseInt, but little modified (replacing throw with return false):

This function has good perfomence and garantee right result:

   public static boolean isInt(String s) {
    int radix = 10;

    if (s == null) {
        return false;
    }

    if (radix < Character.MIN_RADIX) {
        return false;
    }

    if (radix > Character.MAX_RADIX) {
        return false;
    }

    int result = 0;
    boolean negative = false;
    int i = 0, len = s.length();
    int limit = -Integer.MAX_VALUE;
    int multmin;
    int digit;

    if (len > 0) {
        char firstChar = s.charAt(0);
        if (firstChar < '0') { // Possible leading "+" or "-"
            if (firstChar == '-') {
                negative = true;
                limit = Integer.MIN_VALUE;
            } else if (firstChar != '+')
                return false;

            if (len == 1) // Cannot have lone "+" or "-"
                return false;
            i++;
        }
        multmin = limit / radix;
        while (i < len) {
            // Accumulating negatively avoids surprises near MAX_VALUE
            digit = Character.digit(s.charAt(i++), radix);
            if (digit < 0) {
                return false;
            }
            if (result < multmin) {
                return false;
            }
            result *= radix;
            if (result < limit + digit) {
                return false;
            }
            result -= digit;
        }
    } else {
        return false;
    }
    return true;
}
Jacquerie answered 5/7, 2019 at 12:42 Comment(0)
J
0

You could:

  1. Check that the string is a number
  2. Check that it is not too long to be parsed as a long
  3. Check if the resulting long value is small enough to be represented by an int

(Assuming you for some reason would have to implement this yourself: you should probably first take a look at com.google.common.primitives.Ints.tryParse(String) and see if that is good enough for your purposes (as suggested in another answer).)

// Credit to Rastislav Komara’s answer: https://mcmap.net/q/94137/-what-39-s-the-best-way-to-check-if-a-string-represents-an-integer-in-java
private static final Pattern nonZero = Pattern.compile("^-?[1-9]\\d*$");

// See if `str` can be parsed as an `int` (does not trim)
// Strings like `0023` are rejected (leading zeros).
public static boolean parsableAsInt(@Nonnull String str) {
    if (str.isEmpty()) {
        return false;
    }
    if (str.equals("0")) {
        return true;
    }
    if (canParseAsLong(str)) {
        long value = Long.valueOf(str);
        if (value >= Integer.MIN_VALUE && value <= Integer.MAX_VALUE) {
            return true;
        }
    }
    return false;
}

private static boolean canParseAsLong(String str) {
    final int intMaxLength = 11;
    return str.length() <= intMaxLength && nonZero.matcher(str).matches();
}

This method can also be converted to return Optional<Integer> so that you don’t have to parse the string twice in the client code (once to check if it’s possible and the second time to do it “for real”). For example:

if (canParseAsLong(str)) {
    long value = Long.valueOf(str);
    if (value >= Integer.MIN_VALUE && value <= Integer.MAX_VALUE) {
        return Optional.of((int) value);
    }
}
Jarrett answered 22/6, 2020 at 17:17 Comment(0)
A
0

a little improvement to @Jonas K anwser, this function will rule out one single operator like "*".

public boolean isInteger(String str) {
    // null pointer
    if (str == null) {
        return false;
    }
    int len = str.length();
    // empty string
    if (len == 0) {
        return false;
    }
    // one digit, cannot begin with 0
    if (len == 1) {
        char c = str.charAt(0);
        if ((c < '1') || (c > '9')) {
            return false;
        }
    }

    for (int i = 0; i < len; i++) {
        char c = str.charAt(i);
        // check positive, negative sign
        if (i == 0) {
            if (c == '-' || c == '+') {
                continue;
            }
        }
        // check each character matches [0-9]
        if ((c < '0') || (c > '9')) {
            return false;
        }
    }
    return true;
}

Affray answered 28/7, 2020 at 21:28 Comment(0)
C
0

I recently (today) needed to figure out a quick way to do this and of course I was going to use the exception approach for ease when the monkey on the shoulder (conscience) woke up so it took me down this old familiar rabbit hole; no exceptions are not that much more expensive in fact sometimes exceptions are faster (old AIX multiprocessor systems) but regardless it’s to elegant so I did something that the younger me never did and to my amazement nobody here did either (apologize if someone did and I missed it I honestly did not find) : so what did I think we all missed; taking a look at how the JRE implemented it, yes they threw an exception but we can always skip that part.

The younger me from 10 years ago would have felt this to be beneath him, but then again he is a loud mouthed show off with a poor temperament and a god complex so there is that.

I am putting this here for the benefit of anyone coming here in the future. Here is what I found:

public static int parseInt(String s, int radix) throws NumberFormatException
{
    /*
     * WARNING: This method may be invoked early during VM initialization
     * before IntegerCache is initialized. Care must be taken to not use
     * the valueOf method.
     */

    if (s == null) {
        throw new NumberFormatException("null");
    }

    if (radix < Character.MIN_RADIX) {
        throw new NumberFormatException("radix " + radix +
                                        " less than Character.MIN_RADIX");
    }

    if (radix > Character.MAX_RADIX) {
        throw new NumberFormatException("radix " + radix +
                                        " greater than Character.MAX_RADIX");
    }

    int result = 0;
    boolean negative = false;
    int i = 0, len = s.length();
    int limit = -Integer.MAX_VALUE;
    int multmin;
    int digit;

    if (len > 0) {
        char firstChar = s.charAt(0);
        if (firstChar < '0') { // Possible leading "+" or "-"
            if (firstChar == '-') {
                negative = true;
                limit = Integer.MIN_VALUE;
            } else if (firstChar != '+')
                throw NumberFormatException.forInputString(s);

            if (len == 1) // Cannot have lone "+" or "-"
                throw NumberFormatException.forInputString(s);
            i++;
        }
        multmin = limit / radix;
        while (i < len) {
            // Accumulating negatively avoids surprises near MAX_VALUE
            digit = Character.digit(s.charAt(i++),radix);
            if (digit < 0) {
                throw NumberFormatException.forInputString(s);
            }
            if (result < multmin) {
                throw NumberFormatException.forInputString(s);
            }
            result *= radix;
            if (result < limit + digit) {
                throw NumberFormatException.forInputString(s);
            }
            result -= digit;
        }
    } else {
        throw NumberFormatException.forInputString(s);
    }
    return negative ? result : -result;
}
Coypu answered 27/9, 2020 at 14:15 Comment(0)
B
0

For kotlin, isDigitsOnly() (Also for Java's TextUtils.isDigitsOnly()) of String always returns false it has a negative sign in front though the rest of the character is digit only. For example -

/** For kotlin*/
var str = "-123" 
str.isDigitsOnly()  //Result will be false 

/** For Java */
String str = "-123"
TextUtils.isDigitsOnly(str) //Result will be also false 

So I made a quick fix by this -

 var isDigit=str.matches("-?\\d+(\\.\\d+)?".toRegex()) 
/** Result will be true for now*/
Bugle answered 12/12, 2020 at 7:26 Comment(0)
U
-1
Number number;
try {
    number = NumberFormat.getInstance().parse("123");
} catch (ParseException e) {
    //not a number - do recovery.
    e.printStackTrace();
}
//use number
Umeh answered 26/10, 2008 at 8:7 Comment(0)
A
-1

For those readers who arrive here like me years after the question was asked, I have a more general solution for this question.

/**
 * Checks, if the string represents a number.
 *
 * @param string the string
 * @return true, if the string is a number
 */
public static boolean isANumber(final String string) {
    if (string != null) {
        final int length = string.length();
        if (length != 0) {
            int i = 0;
            if (string.charAt(0) == '-') {
                if (length == 1) {
                    return false;
                }
                i++;
            }
            for (; i < length; i++) {
                final char c = string.charAt(i);
                if ((c <= PERIOD) || ((c >= COLON))) {
                    final String strC = Character.toString(c).toUpperCase();
                    final boolean isExponent = strC.equals("E");
                    final boolean isPeriod = (c == PERIOD);
                    final boolean isPlus = (c == PLUS);

                    if (!isExponent && !isPeriod && !isPlus) {
                        return false;
                    }
                }
            }
            return true;
        }
    }
    return false;
}
Arva answered 13/5, 2014 at 11:30 Comment(1)
Try/catch is designed to be used when you really don't have control over what could go wrong. In this case - you can and the accepted answer is still a good solution today. Also, throwing exceptions is expensive and should be avoided.Kossuth
C
-1

Find this may helpful:

public static boolean isInteger(String self) {
    try {
        Integer.valueOf(self.trim());
        return true;
    } catch (NumberFormatException nfe) {
        return false;
    }
}
Clarissa answered 4/7, 2015 at 7:30 Comment(0)
C
-1
public class HelloWorld{

    static boolean validateIP(String s){
        String[] value = s.split("\\.");
        if(value.length!=4) return false;
        int[] v = new int[4];
        for(int i=0;i<4;i++){
            for(int j=0;j<value[i].length();j++){
                if(!Character.isDigit(value[i].charAt(j))) 
                 return false;
            }
            v[i]=Integer.parseInt(value[i]);
            if(!(v[i]>=0 && v[i]<=255)) return false;
        }
        return true;
    }

    public static void main(String[] argv){
        String test = "12.23.8.9j";
        if(validateIP(test)){
            System.out.println(""+test);
        }
    }
}
Compartmentalize answered 11/4, 2016 at 5:5 Comment(1)
What’s IP got to do with the question?Jarrett
P
-3
Integer.valueOf(string); 

works for me most of the time!

Purveyance answered 26/10, 2008 at 0:11 Comment(1)
It's that (all - most) of the time that I'm worried about. :)Raid

© 2022 - 2024 — McMap. All rights reserved.