Parsing converts a String that represents a number — "42", "3.14", "-7" — into the corresponding numeric primitive or wrapper type. Java's wrapper classes each provide two static methods for this: parseXxx(String), which returns a primitive, and valueOf(String), which returns a wrapper object. In modern code backed by autoboxing, both are equivalent for most purposes; prefer parseXxx when you need a primitive (no boxing overhead), and valueOf when you need an Integer, Double, or similar wrapper.
Both methods throw NumberFormatException — a RuntimeException — if the string is null, empty, or contains characters that are not valid for the target type. Always validate or handle this exception when parsing untrusted input.
// Primitive parsers
int i = Integer.parseInt("42"); // 42
long l = Long.parseLong("9876543210"); // 9876543210L
double d = Double.parseDouble("3.14"); // 3.14
float f = Float.parseFloat("2.5"); // 2.5f
boolean b = Boolean.parseBoolean("true"); // true (case-insensitive)
boolean b2 = Boolean.parseBoolean("yes"); // false — only "true" is true
// Wrapper valueOf (returns boxed type)
Integer boxed = Integer.valueOf("100");
Double dbl = Double.valueOf("1.5e3"); // 1500.0
// Parsing with a radix (base)
int hex = Integer.parseInt("FF", 16); // 255
int bin = Integer.parseInt("1010", 2); // 10
int oct = Integer.parseInt("17", 8); // 15
// NumberFormatException — must handle for untrusted input
try {
int x = Integer.parseInt("abc");
} catch (NumberFormatException e) {
System.err.println("Not a valid integer: " + e.getMessage());
}
// Safe parse helper using Optional
static OptionalInt tryParseInt(String s) {
try {
return OptionalInt.of(Integer.parseInt(s));
} catch (NumberFormatException e) {
return OptionalInt.empty();
}
}
Integer.parseInt(null) throws NumberFormatException, not NullPointerException. Always null-check before parsing values from user input, HTTP parameters, or configuration files.
Going the other direction — from a number to a String — is generally safer because any number has a valid string representation. Java provides several mechanisms, each with a slightly different purpose.
String.valueOf(number) is the idiomatic general-purpose method — it handles primitives, wrapper objects, and even null (returning the string "null" rather than throwing). Integer.toString(n) and its sibling methods do the same for a specific type. String concatenation with + "" works but obscures intent. String.format() and formatted() are for situations where you need width, padding, precision, or locale-specific formatting.
// String.valueOf — handles any type including null
String s1 = String.valueOf(42); // "42"
String s2 = String.valueOf(3.14); // "3.14"
String s3 = String.valueOf(true); // "true"
String s4 = String.valueOf((Object) null); // "null" — no NullPointerException
// Wrapper toString methods
String s5 = Integer.toString(255); // "255"
String s6 = Integer.toString(255, 16); // "ff" (hex)
String s7 = Integer.toString(10, 2); // "1010" (binary)
String s8 = Integer.toBinaryString(10); // "1010"
String s9 = Integer.toHexString(255); // "ff"
String s10 = Integer.toOctalString(8); // "10"
// String concatenation — simple but less explicit
String s11 = 42 + ""; // "42" — works but adds noise
// String.format — for width, padding, precision
String padded = String.format("%05d", 42); // "00042"
String currency = String.format("%.2f", 3.1); // "3.10"
String hex2 = String.format("%X", 255); // "FF" (uppercase hex)
// Java 15+ — formatted() instance method on String literal
String report = "Value: %d, rate: %.1f%%".formatted(100, 12.5);
// "Value: 100, rate: 12.5%"
For locale-aware output — comma separators, currency symbols, percentage signs — Java's NumberFormat and DecimalFormat classes provide the right abstraction. They separate the value from the presentation rules, which is essential for applications that must display numbers correctly in different countries and languages.
NumberFormat.getInstance(Locale) formats numbers according to a locale's conventions. DecimalFormat gives you full control via a pattern string: # represents an optional digit, 0 represents a mandatory digit (pads with zero), , is the grouping separator, and . is the decimal separator in the pattern (the actual separator depends on the locale).
import java.text.*;
import java.util.Locale;
// Locale-aware number formatting
NumberFormat nf = NumberFormat.getInstance(Locale.US);
System.out.println(nf.format(1234567.89)); // 1,234,567.89
NumberFormat nfDE = NumberFormat.getInstance(Locale.GERMANY);
System.out.println(nfDE.format(1234567.89)); // 1.234.567,89
// Currency
NumberFormat currency = NumberFormat.getCurrencyInstance(Locale.US);
System.out.println(currency.format(1999.99)); // $1,999.99
NumberFormat currencyEU = NumberFormat.getCurrencyInstance(Locale.FRANCE);
System.out.println(currencyEU.format(1999.99)); // 1 999,99 €
// Percentage
NumberFormat pct = NumberFormat.getPercentInstance(Locale.US);
System.out.println(pct.format(0.1234)); // 12%
// DecimalFormat for custom patterns
DecimalFormat df = new DecimalFormat("#,##0.00");
System.out.println(df.format(1234.5)); // 1,234.50
System.out.println(df.format(0.5)); // 0.50
DecimalFormat sci = new DecimalFormat("0.###E0");
System.out.println(sci.format(123456.789)); // 1.235E5
// Parsing formatted strings back to numbers
Number parsed = nf.parse("1,234,567.89");
System.out.println(parsed.doubleValue()); // 1234567.89
DecimalFormat is not thread-safe. Create a new instance per thread or synchronize access when sharing a DecimalFormat across threads. String.format() is thread-safe and sufficient for most simple formatting tasks.
NumberFormatException is an unchecked exception, so the compiler will not force you to handle it. But in any code path that parses user-supplied or externally-sourced strings, failing to handle it means a malformed value silently crashes your application. The right approach depends on context: propagate the exception if the caller should decide how to handle bad input, return an Optional or a default value for soft validation, or validate the format first with a regex or a try-parse utility.
// Pattern 1 — try-parse returning Optional (preferred for user input)
static OptionalInt parseInt(String s) {
if (s == null || s.isBlank()) return OptionalInt.empty();
try {
return OptionalInt.of(Integer.parseInt(s.trim()));
} catch (NumberFormatException e) {
return OptionalInt.empty();
}
}
parseInt("42").ifPresent(v -> System.out.println("Parsed: " + v));
parseInt("abc").ifPresentOrElse(
v -> System.out.println("Parsed: " + v),
() -> System.out.println("Invalid number")
);
// Pattern 2 — default value for missing/malformed config
String config = System.getProperty("timeout.ms", "5000");
int timeout = parseInt(config).orElse(5000);
// Pattern 3 — validate before parsing (useful when error message matters)
static int parsePort(String s) {
try {
int port = Integer.parseInt(s);
if (port < 1 || port > 65535) {
throw new IllegalArgumentException("Port must be 1–65535, got: " + port);
}
return port;
} catch (NumberFormatException e) {
throw new IllegalArgumentException("Invalid port number: " + s, e);
}
}