Overview
It is a daily job for programmers to convert some data type to another. This article will explore approaches to convert a given Java String object to an integer value (primitive type int).
Integer.parseInt
Thanks to the standard Java Class Library, we have parseInt
and parseUnsignedInt
methods on the Integer
class that parse the string argument as a signed or unsigned decimal integer.
/** * Java method demonstrating simple use of parseInt to convert String to integer */ private static void simpleConversion() { int sample1 = Integer.parseInt("0"); // returns 0 int sample2 = Integer.parseInt("47"); // returns 47 int sample3 = Integer.parseInt("+4"); // returns 4 int sample4 = Integer.parseInt("-4"); // returns -4 int sample5 = Integer.parseInt("-0"); // returns 0 /** * The below line prints * 0 * 47 * 4 * -4 * 0 */ IntStream.of(sample1, sample2, sample3, sample4, sample5).forEach(System.out::println); // .parseInt below throws an unchecked NumberFormatException because " 0 xx" is not a valid integer int sample6 = Integer.parseInt(" 0 xx"); //throws Unchecked NumberFormatException }
As we can see, Integer.parseInt
though useful, can be used directly only in very limited use cases where it is guaranteed that the incoming String
will be an integer.
Let’s look at some options to harden our String to int conversion logic.
Option 1 – Continue using Integer.parseInt
and handle NumberFormatException
private int convertStringToInt(String str, int defaultValue){
try {
return Integer.parseInt(str); //return the int if parsing succeeds
}
catch(NullPointerException | NumberFormatException e){
// log the unsuccessful parse if necessary
return defaultValue; //return default value otherwise
}
}
The caller will be required to provide a default value in case the passed string is not parseable. If the passed string is null
or not a valid integer, this method will return the defaultValue
.
We can add some simple sanitization of the String to increase the probability of successful conversion using the String.trim
method.
Our previous code would have returned defaultValue
for " 123 "
but the below code will successfully parse and return 123 if passed " 123 "
private int convertStringToInt(String str, int defaultValue){
try {
return Integer.parseInt(str.trim()); //return the int if parsing succeeds
}
catch(NullPointerException | NumberFormatException e){
return defaultValue; //return default value otherwise
}
}
Option 2 – Simple Regular Expression and avoiding NumberFormatException
private static final String simpleIntegerRegEx = "\\d+";
private static int convertUsingSimpleRegEx(String str, int detaultValue){
// Sanitize the string. Take care of the case where str may be null. Remove leading & trailing spaces
str = str == null? "":str.trim();
// Parse and return the int only if str matches the format for an integer otherwise return defaultValue
return str.matches(simpleIntegerRegEx) ? Integer.parseInt(str) : detaultValue;
}
In the above example, we first want to reinitialize str
to handle null cases and trim any leading and/or trailing spaces. This step is done using –
str = str == null? "":str.trim();
and will make sure we don’t encounter an NPE or NullPointerException later in the method.
The next line return str.matches(simpleIntegerRegEx) ? Integer.parseInt(str) : detaultValue;
does a few things
- Checks whether the sanitized string is in an "integer" format
- Invokes and returns the output of
Integer.parseInt
only if the format check passes - Returns the defaultValue that the caller of the method wants to be returned otherwise
Advantages of this approach –
- Cleaner code
- We are not relying on Exceptions to control flow in the regular happy path
Disadvantages of this approach –
- Matching Strings against regular expressions is expensive
- Overall performance of this approach will be slower than the previous approach
Option 3 – Character by character traversal of the input String
Now let’s suppose we are given a text (String), and we have to identify the first integer in the string. For example, given input string " sample text to find the integer 123 and not 456"
our method should be able to extract int value 123
Here is one way to do that-
- We can traverse the string character by character and check if each character is a digit or not.
- As soon as we find the first digit, we record its position and continue traversing until we encounter digits.
- As soon as we encounter a non-digit character, we stop traversing, and then we use the recorded position of start and end of digit characters to get a substring
- This substring can be safely converted to int using parseInt
Here is the code snippet for the above approach –
private static void charBycharFindDigits(){
String sampleString = " sample text to find the integer 123 and not 456 ";
int integerStartIndex = 0, integerEndIndex = 0;
// find the position of the first digit
while (integerStartIndex < sampleString.length() && !Character.isDigit(sampleString.charAt(integerStartIndex)))
integerStartIndex++;
// We have found the first digit. Continue traversing until we continue to see digits.
integerEndIndex = integerStartIndex;
while (integerEndIndex < sampleString.length() && Character.isDigit(sampleString.charAt(integerEndIndex)))
integerEndIndex++;
// evaluates result to 123
int result = Integer.parseInt(sampleString.substring(integerStartIndex, integerEndIndex));
System.out.println("First Integer:" + result);
}
One limitation of the above code is that it will not detect negative integers. i.e. the above snippet will continue to print ”123” even if the sample string was "String sampleString = " sample text to find the integer -123 and not 456 ";
For text -123
in a given string, we obviously want our code to return integer value -123 and not 123
We can fix this by adding the below snippet AFTER evaluating result
–
//check if our found integer is actually a negative integer
if(integerStartIndex> 1 && sampleString.charAt(integerStartIndex-1) == '-')
result = -result;
System.out.println("First Integer:" + result);
Option 4 – Using Pattern Matcher
Now let’s suppose we are given a text (String), and we have to identify all the integers in the string.
For example, given input string "This is a string with not 1 but -3 integers. Third one is a random 3421"
our method should be able to extract an integer array with values 1, -3 and 3421
We can use Matcher with an appropriate regular expression to find all the integers in a given string. Here how the code snippet would look like –
private static int[] extractUsingPatternMatcher(String str){
Matcher matcher = Pattern.compile("([-+]?[0-9]+)").matcher(str);
return matcher.results().mapToInt((mr -> Integer.parseInt(mr.group()))).toArray();
}
We are using regular expression "([-+]?[0-9]+)"
to match patterns in the string. Each match will represent an integer (positive or negative).
The next line, matcher.results()
returns a Stream of the matched results, each of which represents an integer but in a String literal format. We then use Streams.mapToInt()
to convert the MatchResult
stream to an IntStream. The IntStream is then converted to an integer array using toArray()
The above can be tested by passing it a String and then printing the array it returns.
int[] detectedInts = extractUsingPatternMatcher("This is a string with not 1 but -3 integers. third one is a random 3421");
// print the contents of an integer array using Streams
Arrays.stream(detectedInts).forEach(System.out::println);
The above snippet will print
1
-3
3421
Conclusion
In this article, we have looked at various scenarios for converting string or part(s) of the string to int and solutions for each of the scenarios along with their nuances.