Java String Conversions
Convert between Java strings and primitives — Integer.parseInt, Double.parseDouble, String.valueOf, and more.
Most data arrives as text and most data leaves as text. Between those two boundaries it usually lives as something more useful — an int, a double, a boolean, a LocalDate. This chapter is about the two directions of conversion between String and the primitive types, the wrapper types, and arrays of characters.
There's a small vocabulary worth memorising; once you know it, the answer to "how do I turn this string into an X" is a one-liner every time.
String → primitive: the parse... family
Every wrapper class has a static method that takes a String and returns the corresponding primitive:
int i = Integer.parseInt("42");
long l = Long.parseLong("9999999999");
double d = Double.parseDouble("3.14");
float f = Float.parseFloat("3.14");
short s = Short.parseShort("32000");
byte b = Byte.parseByte("127");
boolean ok = Boolean.parseBoolean("true"); // any case-insensitive "true"; everything else → falseThese are the standard tools. They throw NumberFormatException for input that doesn't parse — including null, empty strings, whitespace-padded strings, locale-specific decimals like "3,14", and out-of-range values.
Integer.parseInt(" 42 "); // NumberFormatException — trim first
Integer.parseInt("3.0"); // NumberFormatException — that's a double
Integer.parseInt("1234567890123"); // NumberFormatException — overflows intInteger.parseInt accepts an optional second argument for the radix:
Integer.parseInt("ff", 16); // 255
Integer.parseInt("1010", 2); // 10
Integer.parseInt("777", 8); // 511 — the radix is the second arg, not a prefix
Integer.parseInt("0x1A", 16); // NumberFormatException — no "0x" prefix; pass just "1A"parseInt reads the literal digits in the radix you pass; it does not understand source-code prefixes like 0x or a leading 0 for octal. So Integer.parseInt("0777", 8) is fine — the leading 0 is simply another octal digit — but Integer.parseInt("0x1A", 16) throws, because x isn't a base-16 digit. Strip any prefix yourself before parsing.
For unsigned interpretation of the high bit on 32- and 64-bit values, the JDK adds Integer.parseUnsignedInt and Long.parseUnsignedLong.
String → wrapper: valueOf vs parse...
The static valueOf on each wrapper does the same parse but returns the wrapper type:
Integer n = Integer.valueOf("42"); // Integer, not int
Double d = Double.valueOf("3.14"); // Double, not doubleThe two differ in three places that occasionally matter:
- Return type.
parseInt→int,valueOf→Integer. Pick whichever your sink wants. - Caching.
Integer.valueOf(int)andLong.valueOf(long)cache small numbers (-128..127by default), returning the sameIntegerinstance for repeated calls.parseIntreturns a primitive, so caching is moot — but when you'd be boxing the result anyway,valueOfis cheaper. - Behaviour on overflow. Identical — both throw
NumberFormatException.
Rule of thumb: if you want a primitive, use parseInt; if you want a wrapper, use valueOf. Don't write Integer.valueOf(Integer.parseInt(s)) — that's two parses worth of code for one parse worth of result.
Primitive → String: String.valueOf and friends
The reverse direction has two well-named tools:
String s1 = String.valueOf(42); // "42"
String s2 = String.valueOf(3.14); // "3.14"
String s3 = String.valueOf(true); // "true"
String s4 = String.valueOf('a'); // "a"
String s5 = String.valueOf(new char[]{'h','i'}); // "hi"
String s6 = String.valueOf((Object) null); // "null" — NOT an NPEEvery wrapper also has a toString that takes the primitive:
Integer.toString(42); // "42"
Integer.toString(255, 16); // "ff" — radix overload
Long.toString(123456789L); // "123456789"
Double.toString(3.14); // "3.14"And of course, concatenation with "" works:
String s = "" + 42; // "42"String.valueOf is the most general and the most defensible style — it never throws on null and handles every primitive plus Object. For numeric formatting where you need width, sign, grouping, or locale-aware decimals, reach for String.format instead.
Strings and chars
A char is a primitive (one UTF-16 code unit); a String is a sequence of them. Conversions in both directions:
String s = String.valueOf('a'); // "a"
char c1 = "abc".charAt(0); // 'a'
char[] arr = "abc".toCharArray(); // ['a', 'b', 'c']
String s2 = new String(arr); // "abc"
String s3 = new String(arr, 1, 2); // "bc" — offset + countString.toCharArray() always returns a fresh, modifiable array. That's the right tool when you need to mutate characters (e.g. to wipe out a password buffer) — String itself cannot give you a mutable view.
Strings and bytes
Bytes are the wire format; strings are the in-memory form. Conversion always involves a charset, and the right answer is always to pass it explicitly:
byte[] bytes = "héllo".getBytes(StandardCharsets.UTF_8);
String back = new String(bytes, StandardCharsets.UTF_8);The no-arg overloads (getBytes(), new String(bytes)) use the JVM's default charset, which is platform-dependent and a constant source of "works on my machine" bugs. Always pass a Charset. UTF-8 is the right default for new code; legacy systems sometimes need Latin-1 or one of the Windows code pages.
Conversions that don't exist
A few conversions people reach for that aren't there:
int→charby digit value.(char) 5is the control character at code point 5, not'5'. UseCharacter.forDigit(5, 10)or(char) ('0' + 5).char→intby digit value.(int) '5'is 53, not 5. UseCharacter.digit('5', 10)or'5' - '0'.String→ numeric with default on failure. Java doesn't ship aparseIntOrDefault. The idiomatic version is a tiny helper:
static int parseIntOr(String s, int fallback) {
try { return Integer.parseInt(s); }
catch (NumberFormatException e) { return fallback; }
}Conversion is not validation
The single biggest mistake with string-to-primitive conversion is treating a successful parse as a successful validation. Integer.parseInt("0") returns 0 for any input the user types as zero, including "0", "00", "+0", and "-0" — all of which parse to the same value. If you care whether the input was canonical, parse and then convert back:
int v = Integer.parseInt(input);
if (!Integer.toString(v).equals(input)) {
throw new IllegalArgumentException("non-canonical integer: " + input);
}For numeric inputs from human-facing forms, validate the format first (regex, length, allowed characters), then parse. Don't lean on the parser to tell you whether the input was reasonable.
A worked example
A program that converts in both directions across the most common types, including a robust default-on-failure helper, a hex round-trip, and a byte/string round-trip with UTF-8.
Three details to notice in the output. The héllo string round-trips through UTF-8 cleanly — five characters becomes six bytes (the é takes two), and the resulting bytes parse back into the same five characters. The String.valueOf((Object)null) produces "null" rather than throwing — that's deliberate; it's why "x = " + nullable doesn't blow up. And the parseIntOr helper handles bad input, padded input, and null input without your call site needing to know.
What's next
The chapter that closes Part 9 covers the two most-used "string in, list out / list in, string out" methods in the standard library — and the regex-flavoured variants that sit beneath them. Continue to Java String split() and join().