Java Double.parseDouble: Parsing Strings to Doubles
See how to use Double.parseDouble to convert strings to primitive doubles, handle invalid input and locale-specific numbers, and choose between parseDouble and valueOf.
Converting a String into a primitive double in Java is usually done with Double.parseDouble(String s). It returns a primitive double, throws NumberFormatException for invalid input, and has a few behaviors that often surprise developers. This article explains how parseDouble works, where it fails, and how to handle real-world inputs safely.
How Double.parseDouble Works
Double.parseDouble is a static method on the Double wrapper class. It accepts a String and returns a primitive double. The conversion rules are the same as those used by Double.valueOf, but the return types differ: parseDouble returns a primitive, while valueOf returns a Double object.
String input = "3.14159"; double value = Double.parseDouble(input); System.out.println(value); // 3.14159
Passing null throws NullPointerException, not NumberFormatException. This matters when handling user input where null might represent a missing value.
String input = null; try { double value = Double.parseDouble(input); // throws NullPointerException } catch (NullPointerException e) { // handle missing input }
The accepted format is the grammar used by Double.valueOf: optional leading or trailing whitespace, an optional leading sign, decimal digits, an optional decimal point, an optional exponent such as 1.0e10, and the special values NaN, Infinity, and -Infinity. Locale-specific decimal separators are not accepted; the decimal point is always .. Grouping separators such as commas are not accepted either.
Handling NumberFormatException
The most common failure mode is malformed input. Any string that does not conform to the expected format triggers NumberFormatException.
String bad = "12,345.67"; try { double value = Double.parseDouble(bad); // throws NumberFormatException } catch (NumberFormatException e) { // handle invalid format }
In practice, wrap parsing in a try-catch whenever the input comes from external sources such as configuration files, user input, or network payloads. Ignoring the exception and assuming valid input leads to runtime failures that are hard to trace.
A more robust approach is to centralize parsing in a utility method that returns an OptionalDouble or a sensible fallback.
public static OptionalDouble parseDoubleSafely(String input) { if (input == null) { return OptionalDouble.empty(); } try { return OptionalDouble.of(Double.parseDouble(input.trim())); } catch (NumberFormatException e) { return OptionalDouble.empty(); } }
OptionalDouble is available since Java 8 and avoids sentinel values like -1 or Double.MIN_VALUE.
Locale and Formatting Pitfalls
Double.parseDouble is locale-independent, which is both a strength and a trap. It always expects a dot as the decimal separator. If your application reads numbers from a locale that uses a comma, preprocess the input or use java.text.NumberFormat.
String localized = "3,14"; // Double.parseDouble(localized) throws NumberFormatException
To parse locale-aware numbers, use NumberFormat with the appropriate Locale. This is common in financial or scientific applications where users input numbers in their local format.
import java.text.NumberFormat; import java.text.ParseException; import java.util.Locale; NumberFormat format = NumberFormat.getInstance(Locale.GERMANY); try { Number parsed = format.parse("3,14"); double value = parsed.doubleValue(); // 3.14 } catch (ParseException e) { // handle parse failure }
Note that NumberFormat.parse does not fully validate the string by default; it may accept a prefix such as 3,14abc and return 3.14. Use ParsePosition to ensure the entire string is consumed if strict validation is needed.
Special Values: NaN and Infinity
Double.parseDouble accepts the exact strings "NaN", "Infinity", and "-Infinity". They are case-sensitive, so "nan" or "infinity" throw NumberFormatException. This often surprises developers: a string like "NaN" parses successfully into a double that is not a number.
double nan = Double.parseDouble("NaN"); double posInf = Double.parseDouble("Infinity"); double negInf = Double.parseDouble("-Infinity");
The resulting double values behave according to IEEE 754. NaN compares false to everything, including itself, so use Double.isNaN() to detect it.
double value = Double.parseDouble("NaN"); if (Double.isNaN(value)) { System.out.println("Not a number"); }
This is important when parsing user inputs that might deliberately contain "NaN" as an error marker. If your domain does not allow such values, validate after parsing.
Double.parseDouble vs Double.valueOf
Both methods parse the same string grammar, but they return different types. parseDouble returns a primitive double; valueOf(String) returns a Double object. Choose based on whether you need a primitive or an object for collections or generic APIs. Unlike Integer.valueOf, Double.valueOf does not provide a meaningful cache for arbitrary floating-point values, so there is no performance reason to prefer one over the other for primitive use.
| Method | Return type | Typical use |
|---|---|---|
Double.parseDouble(String) | double (primitive) | Numeric calculations, storing in primitive arrays |
Double.valueOf(String) | Double (wrapper) | Collections that require objects, generic APIs |
When you assign both results to a primitive double, autounboxing produces the same numeric value. Use parseDouble for clarity when you intentionally want a primitive.
Performance and Runtime Behavior
Parsing a string to a double is not free. The method validates the string and then converts the significand and exponent to a binary double. If you parse millions of numbers in a loop, the cost can matter, but exact timings depend on the JVM, input format, and hardware. Profile before optimizing.
The standard library does not provide a separate high-throughput parser. A custom parser for a restricted input format may be faster, but it must handle all valid forms and edge cases accurately. Before writing one, measure whether parsing actually appears in your profiler.
A useful optimization is to avoid reparsing fixed constants:
private static final double TAX_RATE = Double.parseDouble("0.19");
Static final fields ensure the parsing happens once at class load time.
Practical Decision Criteria
Choose Double.parseDouble when you need a primitive double and you can guarantee the input is in the standard format. Use Double.valueOf when you need a Double object for collections or generics. Use NumberFormat when input is locale-dependent. For very high-throughput custom formats, consider a dedicated parser only after profiling shows that standard parsing is a real cost.
Be explicit about how you handle null and invalid strings. A helper method that returns OptionalDouble is a clean way to avoid scattered try-catch blocks. Also remember that Double.parseDouble accepts "NaN" and "Infinity", which may not be valid in your domain. Validate accordingly.
Edge Cases
Leading and trailing whitespace is allowed and ignored. Internal whitespace is not allowed, so a string like "1 000" is invalid. Tabs and newlines at the edges are treated as whitespace, but whitespace between digits is always invalid.
If your input may contain thousands separators, strip them explicitly before calling parseDouble.
String raw = "1,000,000.5"; String normalized = raw.replace(",", ""); double value = Double.parseDouble(normalized); // 1000000.5
This is a simple approach, but beware of locales where the comma is a decimal separator. Only strip commas if you are certain they group thousands, not decimals.
Rounding to the Nearest Double
When a decimal string has more digits than a double can represent exactly, parsing rounds to the nearest representable binary value. The exact result is determined by IEEE 754 rules and cannot be reliably predicted from the decimal text alone. For example, Double.parseDouble("0.1") does not return a mathematical decimal 0.1; it returns the closest binary double, approximately 0.1000000000000000055511151231257827.
When comparing parsed doubles, avoid relying on == with a literal. Use an epsilon comparison when you need approximate equality, and consider BigDecimal when you need exact decimal precision.