W3docs

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 → false

These 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 int

Integer.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 double

The two differ in three places that occasionally matter:

  • Return type. parseIntint, valueOfInteger. Pick whichever your sink wants.
  • Caching. Integer.valueOf(int) and Long.valueOf(long) cache small numbers (-128..127 by default), returning the same Integer instance for repeated calls. parseInt returns a primitive, so caching is moot — but when you'd be boxing the result anyway, valueOf is 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 NPE

Every 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 + count

String.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:

  • intchar by digit value. (char) 5 is the control character at code point 5, not '5'. Use Character.forDigit(5, 10) or (char) ('0' + 5).
  • charint by digit value. (int) '5' is 53, not 5. Use Character.digit('5', 10) or '5' - '0'.
  • String → numeric with default on failure. Java doesn't ship a parseIntOrDefault. 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.

java— editable, runs on the server

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().

Practice

Practice
What's the difference between `Integer.parseInt('42')` and `Integer.valueOf('42')`?
What's the difference between `Integer.parseInt('42')` and `Integer.valueOf('42')`?
Was this page helpful?