- Java string to int test
- parseInt() vs. parseUnsignedInt()
- Auto-boxing and -unboxing the result
- Performance of the String-to-int conversion
- Performance of various String-to-int conversion methods
- Performance of String-to-int conversion across Java versions
- Summary
- Java String to Int
- The Integer.parseInt Method
- Handling Parsing Exception
- The Integer.valueOf Method
- Conclusion
Java string to int test
In all the above cases, the number to be parsed must be within the range Integer.MIN_VALUE (= -2 31 = -2,147,483,648) to Integer.MAX_VALUE (= 2 31 -1 = 2,147,483,647). It becomes interesting (not to say: confusing) if, for example, we convert the valid int value 0xCAFEBABE into a hex String and then back into an int:
int hex = 0xCAFEBABE; String s = Integer.toHexString(hex); int i = Integer.parseInt(s, 16);
Code language: Java (java)
Exception in thread "main" java.lang.NumberFormatException: For input string: "cafebabe"
Why is that? First of all: The String s contains «cafebabe» as expected. Why can’t this String be converted back to an int? The reason is that the parseInt() method assumes the given number to be positive unless a minus sign precedes it. If you convert «cafebabe» to the decimal system, you get 3,405,691,582. This number is higher than Integer.MAX_INT and therefore, cannot be represented as an int. Then why can we assign the number to the int variable hex ? The binary representation of the numbers plays an (intended) trick on us. 0xCAFEBABE corresponds to binary 11001010,11111110,10111010,10111110 – a 32-digit binary number with the first bit being 1. In an int – which is always signed in Java – the first bit stands for the sign. If it is 1, the number is negative (for details on negative numbers, see this Wikipedia article). Let’s add some debug output to the code above:
int hex = 0xCAFEBABE; System.out.println("hex hljs-string">"hex binary hljs-string">"s hljs-keyword">int i = Integer.parseInt(s, 16); System.out.println("i shcb-language" >Code language: Java (java)
These methods allow us to parse numbers in the range 0 to 4,294,967,295 (= 0xffffffff hexadecimal or 32 ones in the binary system). In Java 8, we can adjust the penultimate line of the above example as follows:
int i = Integer.parseUnsignedInt(s, 16);
Code language: Java (java)
As output, we don’t see 3,405,691,582. Rather, as the Java int is always signed, -889,275,714, which is the same value we get when we assign 0xCAFEBABE to an int.
And how do we get to 3,405,691,582? Therefore we have to parse «cafebabe» (or «CAFEBABE» – the case is insignificant) into a long:
long l = Long.parseLong(s, 16);
Code language: Java (java)
Finally, what does 3,405,691,582 look like in binary and hexadecimal notation?
System.out.println("l binary hljs-string">"l hex shcb-language" >Code language: Java (java)
Again, we get the same representations as for the int value -889,275,714, i.e. 11001010,11111110,10111010,10111110 and «cafebabe». The same binary or hexadecimal number thus leads – depending on whether it is stored in an int or in a long – to a different decimal number (if it is larger than Integer.MAX_VALUE ). In the following section, we’ll take a look at some more examples.
parseInt() vs. parseUnsignedInt()
To illustrate the difference between parseInt() and parseUnsignedInt() once again, I wrote a small program, which you can find here in my GitHub repository, and which parses different (threshold) values using both methods.
In the following table, you find the result summarized (the dashes stand for NumberFormatExceptions):
String | Bemerkung | parseInt() | → Hex | parse Unsigned Int() | → Hex |
-2147483649 | Integer.MIN_VALUE — 1 | — | — | — | — |
-2147483648 | Integer. MIN_VALUE | -2147483648 | 80000000 | — | — |
-1000000000 | -1000000000 | c4653600 | — | — | |
-1 | -1 | ffffffff | — | — | |
0 | 0 | 0 | 0 | 0 | |
1000000000 | 1000000000 | 3b9aca00 | 1000000000 | 3b9aca00 | |
2147483647 | Integer.MAX_VALUE | 2147483647 | 7fffffff | 2147483647 | 7fffffff |
2147483648 | Integer.MAX_VALUE +1 | — | — | -2147483648 | 80000000 |
3000000000 | — | — | -1294967296 | b2d05e00 | |
4294967295 | 2 * Integer.MAX_VALUE + 1 | — | — | -1 | ffffffff |
4294967296 | 2 * Integer.MAX_VALUE + 2 | — | — | — | — |
- In the range 0 to Integer.MAX_VALUE , parseInt() and parseUnsignedInt() return the same results.
- parseInt() also covers the range up to Integer.MIN_VALUE and returns exactly the value passed.
- parseUnsignedInt() covers the range up to 2 * Integer.MAX_VALUE + 1 – with the result in the range above Integer.MAX_VALUE always being a negative number. Its hexadecimal representation, converted to the decimal system, corresponds to the input value.
Auto-boxing and -unboxing the result
We have seen above that there are separate methods to convert a String to an int primitive or an Integer object. But what happens if we use the wrong method?
The first case is not particularly elegant but does not pose a problem either: Integer.parseInt() works internally with primitive values and the result is – just as with Integer.valueOf() – eventually converted into an Integer object by auto-boxing.
The second case is different: here, the result is converted to an Integer object inside Integer.valueOf() and then back to an int primitive when it is assigned to i . IntelliJ recognizes this (Eclipse doesn’t) and displays a warning with the recommendation to replace valueOf() with parseInt() :
We will examine the extent to which the compiler or HotSpot forgives us for this error in the next chapter, «performance».
Performance of the String-to-int conversion
Similar to the last article, I did the following comparison measurements with the Java Microbenchmark Harness – JMH:
- Speed of various String-to-int conversion methods with Java 8:
- parseInt() with positive numbers, positive numbers with preceding plus sign, and negative numbers,
- parseUnsignedInt() with positive numbers and positive numbers with a preceding plus sign,
- valueOf() with positive numbers,
- parseInt() with subsequent conversion into an integer object,
- valueOf() with subsequent conversion into an int primitive,
Performance of various String-to-int conversion methods
You can find the source code of this test in my GitHub repository. The test results are in the results/ directory. The following table shows the performance of the various method calls using Java 8:
Method Operations per second Confidence interval (99,9%) parseInt() positive value 25,157,289 24,959,166 – 25,355,412 parseInt() positive value with plus 25,056,427 24,974,885 – 25,137,970 parseInt() negative value 25,143,740 25,039,972 – 25,247,508 parseUnsignedInt() positive value 25,124,027 25,060,833 – 25,187,221 parseUnsignedInt() positive value with plus 25,015,082 24,914,320 – 25,115,843 parseInt() with subsequent boxing 24,594,336 24,421,316 – 24,767,355 valueOf() positive value 24,531,187 24,413,040 – 24,649,334 valueOf() with subsequent unboxing 24,325,347 24,183,155 – 24,467,538 As you can see, the first five measurements are almost identical. This can be explained quickly: the executed code is the same in all cases. valueOf() and parseInt() with subsequent boxing are about 2% slower. This should correspond to the overhead for converting into an Integer object. valueOf() with subsequent unboxing is about 1% slower, which means that neither the compiler nor HotSpot have forgiven us for the «boxing with subsequent unboxing» error.
Parsing negative numbers should be slightly faster because internally, negative numbers are added up, and in case of a positive number, the result is multiplied by -1. However, there are no differences in the benchmarks. Multiplying by -1 is apparently so fast that even at 25 million multiplications per second, this is of no significance.
Performance of String-to-int conversion across Java versions
Since in the end, all variants of the String-to-int conversion call Integer.parseInt() , I have restricted myself to measuring the performance of calling this particular method across different Java versions. I used the same test class as for the previous test and commented out all methods except integerParsePositiveInt() . I compiled and ran the code with the respective Java versions. You also find the results of these tests in the results/ folder. Here is a summary of the results:
Java version Operations per second Confidence interval (99.9%) Java 7 25,223,117 25,069,748 – 25,376,488 Java 8 25,157,289 24,959,166 – 25,355,412 Java 9 22,580,117 22,471,102 – 22,689,132 Java 10 22,129,425 21,889,153 – 22,369,698 Java 11 23,657,228 23,494,292 – 23,820,165 Java 12 23,604,657 23,385,208 – 23,824,106 Java 13 23,626,048 23,473,823 – 23,778,273 Java 14 23,599,658 23,440,825 – 23,758,490 Interestingly, the Integer.parseInt() method became significantly slower in Java 9 (nearly 10%), again 2% slower in Java 10 and faster again in Java 11, but since then has stayed about 5% behind the performance of Java 7 and 8. To confirm this measurement result, I ran all benchmark tests (which are repeated 25 times anyway) again – with similar results.
In search of the cause, I first compared the source codes of Integer.parseInt() of all Java versions. Versions 7 and 8 are identical. In Java 9, the code was slightly restructured, e.g., variables were declared elsewhere. The algorithm itself was not changed. The minimal code changes should not affect performance. From Java 9 to the Early Access Release of Java 14, there was no further change, except that in Java 12, the radix was included in the error message for non-parseable numbers.
To check whether the changes in Java 9 affected performance, I copied the Integer.parseInt() source codes from Java 8 and 9 and tested these copies with JMH. Both were the same speed. (This test is not in the GitHub repository because I don’t know to what extent I can publish Java source codes.)
In another experiment, I compiled the Integer.parseInt() source code with Java 8 and ran the resulting class file with Java 9 to 14. This led to a similar result as the initial performance test, i.e., Java 9 and 10 were slower, and Java 11 was a bit faster again. The reason for the different speeds must, therefore, lie within the JVM. If any of you know the exact cause, I would be happy to receive an enlightening comment.
Summary
In this article, I have shown how to parse numbers in decimal and other number systems and what the difference is between parseInt() and parseUnsignedInt() . Be careful not to box unnecessarily from int to Integer, or vice versa, or – worst of all – both in a row. If you find the article helpful, I’d be happy if you shared it with one of the following share buttons.
Java String to Int
A common requirement while programming in Java is to convert String to int . UI inputs in Web-based HTML, JSP, or Thymeleaf templates are transferred to backend Java applications as strings. It is the application developer’s responsibility to perform any String to int conversions to fulfill business logic, such as calculating discounts, storing age, and so on.
In this post, I’ll discuss how to convert String in Java to int.
The Integer.parseInt Method
The Integer.parseInt() method takes as input a String and returns an int value.
The code to use this method is.
public int convertWithParseInt(String str)
package springframework.guru; import org.junit.After; import org.junit.Before; import org.junit.Test; import static org.junit.Assert.assertEquals; public class StringToIntConverterTest < private StringToIntConverter stringToIntConverter; String str; @Before public void setUp()< str = "369"; stringToIntConverter=new StringToIntConverter(); >@After public void tearDown() < str = null; >@Test public void convertWithParseInt() < int val= stringToIntConverter.convertWithParseInt(str); System.out.println(val); assertEquals(val, 369); >>
The output on running the test in InteliJ is this.
The Integer class also provides an overloaded parseInt() method that additionally accepts the radix (base) to be used while parsing.
Here is the code to use the overloaded method..
public int convertWithParseIntWithRadix(String str, int radix)
@Test public void convertWithParseIntWithRadix()The output on running the test in InteliJ is this.
Handling Parsing Exception
The parseInt() method throws a NumberFormatException if the String does not contain a parsable int .
Here is a sample code to handle the NumberFormatException gracefully.
public static final int DEFAULT_DEFAULT_PARSED_INT = 0; public int tryConvertWithParseInt(String str) < try < int number = Integer.parseInt(str); return number; >catch(NumberFormatException e) < return DEFAULT_DEFAULT_PARSED_INT; >>
This code returns a default int value whenever a NumberFormatException is thrown by the parseInt() method.
Here is the JUnit test code.
@Test public void tryConvertWithParseInt()
The Integer.valueOf Method
The Integer class also comes with the static valueOf() method to convert String to int . The valueOf() method interprets the String exactly as if it were given to parseInt() . In fact, the valueOf() method internally uses the parseInt() method.
However, valueOf() returns a new Integer object whereas parseInt() returns a primitive int .
The code to parse String using the valueOf() method is this.
public Integer convertWithValueOf(String str) < try < Integer num = Integer.valueOf(str); return num; >catch(NumberFormatException e) < return DEFAULT_PARSED_INT; >>
Here is the JUnit test code.
@Test public void convertWithValueOf()
Note: Similar to parseInt(), the valueOf() method also have an overloaded version that accepts an additional radix value.
Conclusion
Considering Java is a strongly typed language and often interfaces with systems that do not have the type system of Java, converting from a string value to an int value in Java is very common task. As you can see Java provides a number of different ways to convert a string value to an integer value.