To convert a String to an int in Java, we call Integer.parseInt(text), which either returns a primitive int or throws a NumberFormatException when the text is not a whole number. The method Integer.valueOf(text) does the same conversion but returns an Integer object.
We need String to int conversion whenever a number reaches our code as text, such as a quantity from a web form or a page number in a URL parameter.
The following example converts valid text, binary and hex text, and bad input, with the result of each line as a comment.
int age = Integer.parseInt("37"); // 37
Integer boxedAge = Integer.valueOf("37"); // 37 (an Integer object)
int negative = Integer.parseInt("-15"); // -15
int binary = Integer.parseInt("1010", 2); // 10
int hex = Integer.parseInt("ff", 16); // 255
int trimmed = Integer.parseInt(" 37 ".strip()); // 37
int bad = Integer.parseInt("abc"); // NumberFormatException: For input string: "abc"
int tooBig = Integer.parseInt("2147483648"); // NumberFormatException (above Integer.MAX_VALUE)
long big = Long.parseLong("3000000000"); // 3000000000
OptionalInt safe = tryParseInt("abc"); // OptionalInt.empty (helper from section 4.3)
int orZero = NumberUtils.toInt("abc"); // 0 (Apache Commons Lang)
int digit = Character.digit('7', 10); // 7
Notice that “abc” and “2147483648” throw an exception, whereas the helper tryParseInt() and NumberUtils.toInt() give back an empty result or 0.
Next, we look at the rules that parseInt() applies to the text and at the difference from valueOf(). After that, we build a safe helper for bad input and cover big numbers, single characters, streams and console input.
1. How Integer.parseInt() Reads a String
The method Integer.parseInt() reads the text from left to right and turns it into an int, which is a 32-bit signed whole number. The rules are strict, and when the text breaks any of them, the method throws a NumberFormatException.
- The text may start with one – or + sign.
- Every other character must be a digit of the number base (the radix), which is 10 by default.
- Leading zeros are allowed, so “007” becomes 7.
- Spaces are not allowed, not even at the start or the end. When the text can contain spaces, we call strip() first to remove the spaces around the text.
- The value must fit in the int range, which goes from -2147483648 (Integer.MIN_VALUE) to 2147483647 (Integer.MAX_VALUE).
In the table, the first six inputs follow the rules. The last four inputs break one rule each, so parseInt() throws the exception for them.
| Input | Integer.parseInt(input) |
|---|---|
| “37” | 37 |
| “-15” | -15 |
| “+7” | 7 |
| “007” | 7 |
| “2147483647” | 2147483647 |
| “-2147483648” | -2147483648 |
| ” 37″ or “37 “ | NumberFormatException |
| “12.5” | NumberFormatException |
| “1,000” | NumberFormatException |
| “2147483648” | NumberFormatException |
The method parseInt() has three overloads (versions of the method with different parameters). The third overload came in Java 9 and parses only a part of a CharSequence (any text type, such as a String or a StringBuilder). It reads from beginIndex (included) up to endIndex (not included).
public static int parseInt(String s)
public static int parseInt(String s, int radix)
public static int parseInt(CharSequence s, int beginIndex, int endIndex, int radix)
With the index-based overload, we can read a number out of a longer text without creating a substring first. For example, a config line holds “age=37”. The digits are at index 4 and 5, so we pass 4 and 6.
int age = Integer.parseInt("age=37", 4, 6, 10); // 37
2. Integer.parseInt() vs Integer.valueOf()
The method Integer.valueOf(String) calls parseInt() and wraps the result in an Integer object. Integer is the wrapper class of the primitive int, so an Integer can be null and can go into a List or a Map. Both methods accept the same input and throw the same exception.
| Integer.parseInt(text) | Integer.valueOf(text) | |
|---|---|---|
| Return type | primitive int | Integer object |
| Invalid text | NumberFormatException | NumberFormatException |
| Radix overload | yes | yes |
| Caches the result | no | yes, values from -128 to 127 |
| Typical use | arithmetic, counters, array indexes | collections, fields that may be null |
The cache row matters when we compare the results with ==, which checks whether two variables point to the same object. For values from -128 to 127, the method valueOf() returns the same cached object every time. For larger values, it creates a new object on each call, so == gives true for 127 but false for 128.
The Integer cache causes a well-known bug. A unit test compares two parsed quantities with == and passes with the test value 100. In production, a customer orders 200 items, and the same check returns false.
boolean small = Integer.valueOf("127") == Integer.valueOf("127"); // true (same cached object)
boolean large = Integer.valueOf("128") == Integer.valueOf("128"); // false (two objects)
boolean equal = Integer.valueOf("128").equals(Integer.valueOf("128")); // true
We use parseInt() when we need a number to calculate with, and valueOf() only when the code needs an Integer object. We always compare Integer objects with equals(), which compares the values. The JVM option -XX:AutoBoxCacheMax, which we pass to the java command at startup, raises the upper limit of the Integer cache.
3. Converting Binary, Octal and Hex Strings
The radix argument tells parseInt() which number system the text uses, for example radix 2 for binary and radix 16 for hex. After the digits 0 to 9, the letters a to z (upper or lower case) stand for the digits 10 to 35, so the largest radix is 36.
Hex text shows up often in real apps, for example in color codes such as ff8800 and in checksums from a file download page.
int fromBinary = Integer.parseInt("1010", 2); // 10
int fromOctal = Integer.parseInt("17", 8); // 15
int fromHex = Integer.parseInt("ff", 16); // 255
int negativeHex = Integer.parseInt("-FF", 16); // -255
int base36 = Integer.parseInt("zz", 36); // 1295
int prefixed = Integer.parseInt("0xff", 16); // NumberFormatException: For input string: "0xff" under radix 16
The method parseInt() rejects prefixes such as 0x, which Java source code uses to write a hex number, as in 0xff. For text with a prefix, we use Integer.decode(), which reads the radix from the prefix.
- A 0x, 0X or # prefix means hex.
- A leading 0 means octal (base 8).
- No prefix means decimal.
int hex = Integer.decode("0xff"); // 255
int hashHex = Integer.decode("#ff"); // 255
int octal = Integer.decode("010"); // 8 (octal)
int negative = Integer.decode("-0x10"); // -16
int padded = Integer.decode("08"); // NumberFormatException: For input string: "8" under radix 8
The last line shows a trap. The method decode() treats every number with a leading zero as octal, and octal has no digit 8, so a zero-padded decimal such as “08” fails. So we pass zero-padded decimal text to parseInt(). For the opposite direction, from an int to binary or hex text, we use the methods in binary, octal and hex conversions.
4. Handling NumberFormatException
NumberFormatException is an unchecked exception, so the compiler does not force us to catch it. But text from a web form or a file can contain anything, and without a catch, one bad value stops the whole request or batch job.
For example, a nightly job imports order rows from a CSV file, and one row has “3x” in the quantity column. Without a catch, the job stops at that row, and the rows after it are never imported.
4.1. Inputs That Throw the Exception
The exception message repeats the bad input in quotes, so we can spot hidden problems such as a trailing space. JDK 21 and JDK 25 print the same messages.
| Input | Message |
|---|---|
| “abc” | For input string: “abc” |
| “” | For input string: “” |
| null | Cannot parse null string |
| ” 37″ | For input string: ” 37″ |
| “12.5” | For input string: “12.5” |
| “- 5” | For input string: “- 5” |
| “2147483648” | For input string: “2147483648” |
| “ff” | For input string: “ff” |
| “zz” with radix 16 | For input string: “zz” under radix 16 |
A null argument also throws a NumberFormatException, not a NullPointerException.
4.2. Catching the Exception
When a bad value is an error that the user must fix, we catch the exception and return a clear message. A try-catch block around the call is enough.
String input = "3x";
try {
int quantity = Integer.parseInt(input);
System.out.println("Quantity: " + quantity);
} catch (NumberFormatException e) {
System.out.println("Quantity must be a whole number. " + e.getMessage());
}
// Quantity must be a whole number. For input string: "3x"
4.3. A Safe Helper Returning OptionalInt or a Default
Sometimes bad input is expected, for example in optional form fields or in the columns of a file. A try-catch at every call would repeat the same code many times, so we put the try-catch in one small helper method. The helper returns an OptionalInt, a container that holds either one int or nothing.
public static OptionalInt tryParseInt(String text) {
if (text == null) {
return OptionalInt.empty();
}
try {
return OptionalInt.of(Integer.parseInt(text.strip()));
} catch (NumberFormatException e) {
return OptionalInt.empty();
}
}
public static int parseIntOrDefault(String text, int defaultValue) {
return tryParseInt(text).orElse(defaultValue);
}
The helper also calls strip() before parsing, because spaces are the most common cause of the exception. So ” 37 “ parses to 37.
OptionalInt valid = tryParseInt("37"); // OptionalInt[37]
OptionalInt spaced = tryParseInt(" 37 "); // OptionalInt[37]
OptionalInt invalid = tryParseInt("abc"); // OptionalInt.empty
OptionalInt missing = tryParseInt(null); // OptionalInt.empty
int fallback = tryParseInt("abc").orElse(-1); // -1
int pageSize = parseIntOrDefault("40", 20); // 40
int defaultSize = parseIntOrDefault("abc", 20); // 20
We return an OptionalInt when the caller must know that parsing failed. We return a default value only when the default is a correct answer. For example, a page size of 20 is a good default when the URL has no valid size. A default of 0 is a poor choice, because the caller cannot tell the text “0” from the text “abc”.
4.4. NumberUtils.toInt() From Apache Commons Lang
Projects that already use Apache Commons Lang, a library of small helper classes, can call NumberUtils.toInt(). Instead of throwing an exception, the method returns 0 or a default value that we pass in.
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.21.0</version>
</dependency>
int valid = NumberUtils.toInt("37"); // 37
int invalid = NumberUtils.toInt("abc"); // 0
int missing = NumberUtils.toInt(null); // 0
int withDefault = NumberUtils.toInt("abc", -1); // -1
int spaced = NumberUtils.toInt(" 37"); // 0 (no stripping)
The last line shows the difference from our helper. NumberUtils.toInt() does not strip spaces, so ” 37″ becomes the default value. Adding a library only for this one method is not worth it. The helper in section 4.3 has the same behavior in ten lines.
The decision chart sums up which method fits which input. We start at the top and answer one question at a time.

5. Numbers Larger Than Integer.MAX_VALUE
An int holds values up to 2147483647, which is too small for many real values. For example, a 3 GB video upload has about 3000000000 bytes, so parseInt() rejects its file size. The method Long.parseLong() follows the same rules for the 64-bit long type, and BigInteger has no upper limit.
long size = Long.parseLong("3000000000"); // 3000000000
BigInteger huge = new BigInteger("99999999999999999999"); // 99999999999999999999
int wrong = (int) Long.parseLong("3000000000"); // -1294967296 (wrong, no error)
int exact = Math.toIntExact(Long.parseLong("3000000000")); // ArithmeticException: integer overflow
Notice the (int) cast in the third line. The cast keeps only the lowest 32 bits of the long value, so we get a wrong number and no error. The method Math.toIntExact() also converts a long to an int, but it throws an ArithmeticException when the value does not fit.
Java has more exact arithmetic methods, such as Math.addExact(), which throw on overflow instead of returning a wrong value. For more on the long type, read converting a String to long.
Some systems send unsigned 32-bit values (values with no sign that are never negative), such as checksums. The method Integer.parseUnsignedInt() accepts unsigned text up to 4294967295. Java has no unsigned int type, so the method stores the result as a negative int, and Integer.toUnsignedString() turns the value back into the original text.
int checksum = Integer.parseUnsignedInt("4294967295"); // -1
String text = Integer.toUnsignedString(checksum); // "4294967295"
6. Converting a Single char to an int
A char holds one character, such as ‘7’. A char is not a String, so we cannot pass it to parseInt(). Java has three ways to get the digit value of a character, and they give different results for characters that are not decimal digits.
int numeric = Character.getNumericValue('7'); // 7
int digit = Character.digit('7', 10); // 7
int subtracted = '7' - '0'; // 7
int letterNumeric = Character.getNumericValue('a'); // 10 (a is the digit 10 in base 36)
int letterDigit = Character.digit('a', 10); // -1 (not a decimal digit)
int dash = Character.getNumericValue('-'); // -1
For decimal digits, Character.digit(c, 10) is the safest choice, because it returns -1 for every non-digit. The method Character.getNumericValue() returns 10 to 35 for the letters a to z, which many developers do not expect. The subtraction ‘7’ – ‘0’ works only for the ASCII digits ‘0’ to ‘9’ and gives a wrong number for any other character.
The method Character.digit() can also add up the digits of a number. For “2026”, the sum is 2 + 0 + 2 + 6 = 10.
int digitSum = "2026".chars().map(c -> Character.digit(c, 10)).sum(); // 10
7. Parsing Strings in a Stream
The call mapToInt(Integer::parseInt) turns a stream of strings into an IntStream, a stream of plain int values with methods such as sum() and max(). When a List needs Integer objects, we use map(Integer::valueOf) instead.
For example, a shopping cart page sends the quantity of each item as a list of strings, and the server adds them up.
List<String> quantities = List.of("5", "3", "8");
int total = quantities.stream().mapToInt(Integer::parseInt).sum(); // 16
List<Integer> numbers = quantities.stream().map(Integer::valueOf).toList(); // [5, 3, 8]
One bad value stops the whole stream with an exception. The helper tryParseInt() from section 4.3 fixes this. With flatMapToInt(), an empty OptionalInt becomes an empty stream, so the stream skips the invalid values, and “x” and “” add nothing to the sum.
List<String> userInput = List.of("5", "x", " 3 ", "", "8");
int crashed = userInput.stream().mapToInt(Integer::parseInt).sum(); // NumberFormatException: For input string: "x"
int validTotal = userInput.stream()
.flatMapToInt(s -> tryParseInt(s).stream())
.sum(); // 16 (5 + 3 + 8)
int[] withDefaults = Stream.of("5", "x", "8")
.mapToInt(s -> parseIntOrDefault(s, 0))
.toArray(); // [5, 0, 8]
For more patterns, read handling exceptions in streams. To convert arrays instead of lists, use the steps in String array to Integer array.
8. Reading an int From User Input
Console input always comes in as text, so we must parse it. Java 25 finalized compact source files and instance main methods, together with the java.lang.IO class. A compact source file needs no class declaration, only a main() method, so a small program reads a number and handles bad input in a few lines.
void main() {
String text = IO.readln("Age: ").strip();
try {
int age = Integer.parseInt(text);
IO.println("Next year: " + (age + 1));
} catch (NumberFormatException e) {
IO.println("Please type a whole number, such as 37.");
}
}
We run the program with java AgeInput.java. When we type 37, the program prints the age for next year. When we type abc, parseInt() throws the NumberFormatException from section 4.1, and the catch block asks for a whole number instead of stopping the program.
Age: 37
Next year: 38
Age: abc
Please type a whole number, such as 37.
A Scanner reads typed values, called tokens, and skips the spaces between them. For text such as “abc”, the method nextInt() throws an InputMismatchException, not a NumberFormatException. So we call hasNextInt() first, which checks that the next token is a whole number.
Scanner scanner = new Scanner("37 abc"); // or new Scanner(System.in)
int first = scanner.nextInt(); // 37
boolean nextIsInt = scanner.hasNextInt(); // false ("abc" is next)
To choose between Scanner, BufferedReader, Console and IO, read reading input from the console.
9. String to int FAQs
9.1. How Do I Convert “12.5” or “1,234” to an int?
We parse the text with a type that understands decimals or separators, and convert the result to an int. The method parseInt() rejects both texts, because a dot and a comma are not digits.
int truncated = (int) Double.parseDouble("12.7"); // 12 (cuts off the fraction)
int rounded = (int) Math.round(Double.parseDouble("12.7")); // 13
int exact = new BigDecimal("12.7").intValueExact(); // ArithmeticException: Rounding necessary
int grouped = NumberFormat.getIntegerInstance(Locale.US)
.parse("1,234").intValue(); // 1234 (parse() throws the checked ParseException)
int cleaned = Integer.parseInt("1,234".replace(",", "")); // 1234
The method intValueExact() throws when the number has a fraction, so it is the right choice when a fraction means bad data. NumberFormat reads the grouping separators of the given locale (a language and country setting). For example, with Locale.GERMANY, the text “1.234” also returns 1234.
Rounding has its own rules for negative numbers, e.g. Math.round(-12.5) returns -12. The rounding methods guide compares round() with ceil() and floor().
9.2. How Do I Check if a String Is a Valid int Before Parsing?
We call tryParseInt() from section 4.3, because the parse itself is the most reliable check. A regular expression such as [-+]?\d+ is not enough, because the pattern still accepts “99999999999”, which is too big for an int.
The Commons Lang methods check something different from “is this an int“, so they give surprising answers.
boolean signed = NumberUtils.isParsable("-37"); // true
boolean decimal = NumberUtils.isParsable("12.5"); // true (but parseInt() throws)
boolean digits = NumberUtils.isDigits("-37"); // false (the sign is not a digit)
9.3. Does parseInt() Accept Digits From Other Languages?
Yes. The method parseInt() accepts every character that Character.digit() treats as a digit, so non-ASCII digits such as Arabic-Indic or Devanagari digits work too. Non-ASCII digits show up when a user types a number on a phone keyboard set to Arabic or Hindi.
int arabic = Integer.parseInt("\u0661\u0662"); // 12 (Arabic-Indic digits)
int devanagari = Integer.parseInt("\u0967\u0968"); // 12 (Devanagari digits)
int fullWidth = Integer.parseInt("\uFF11\uFF12"); // 12 (full-width digits)
When an input field must contain only 0 to 9, we check the text with a pattern such as [0-9]+ before parsing.
9.4. Is Integer.parseInt() Faster Than Integer.valueOf()?
Yes, but only slightly. The method valueOf() calls parseInt() and boxes the result (wraps the int in an Integer object), so it does a little more work. The difference matters only in tight loops over millions of values, so we choose by return type, as we saw in section 2, not by speed.
9.5. How Do I Convert an int Back to a String?
We call Integer.toString(37) or String.valueOf(37), and both return “37”. For padding and number formats, read converting an int to a String.
10. Conclusion
The method Integer.parseInt() converts a String to an int. The text may hold one sign and digits, and the value must fit in the int range, or the method throws a NumberFormatException. When we need an Integer object, we call Integer.valueOf() instead.
For text in other number systems, we pass a radix, or call Integer.decode() when the text has a 0x or # prefix. Values above Integer.MAX_VALUE go to Long.parseLong() or BigInteger.
Untrusted input needs one more step. We strip the text and parse it through a small helper that returns an OptionalInt or a default value, so one bad value never stops a request or a batch job.
11. References
- Integer JavaDoc (Java 25)
- NumberFormatException JavaDoc (Java 25)
- Character JavaDoc (Java 25)
- Long JavaDoc (Java 25)
- IO JavaDoc (Java 25)
- NumberUtils JavaDoc (Commons Lang)
Happy Learning !!