82

Is there a native way (preferably without implementing your own method) to check that a string is parseable with Double.parseDouble()?

Sled
  • 18,541
  • 27
  • 119
  • 168
Louis Rhys
  • 34,517
  • 56
  • 153
  • 221

6 Answers6

71

Apache, as usual, has a good answer from Apache Commons-Lang in the form of NumberUtils.isCreatable(String).

Handles nulls, no try/catch block required.

BullyWiiPlaza
  • 17,329
  • 10
  • 113
  • 185
bluedevil2k
  • 9,366
  • 8
  • 43
  • 57
69

You can always wrap Double.parseDouble() in a try catch block.

try
{
  Double.parseDouble(number);
}
catch(NumberFormatException e)
{
  //not a double
}
jdc0589
  • 6,972
  • 5
  • 36
  • 39
  • 10
    This would be my preferred method because your guaranteed to get exactly the same behavior as the parse. It's very easy with a custom regular expression to overlook edge cases. – Chris Nava Aug 23 '10 at 02:17
  • 2
    This is good EXCEPT if you type in a number followed by a space, it doesn't catch it. – giant91 Sep 06 '13 at 05:03
  • 3
    @giant91 - just trim the number: `number.trim()`. – Bobby Jul 15 '16 at 15:24
  • 2
    @giant91 So? The string is parseable, which is the actual question. – user207421 Jan 27 '17 at 00:55
  • 2
    I like this better than the accepted answer. This is guaranteed to work in all future versions of Java, whereas using RegEx tries to be smart and anticipate parser behavior. Regex are very slow anyway, it's not like trying to find out the string is suitable will save you much time over simply trying to parse it and going through the exception-catching process. – Gabriel Magana Jan 08 '19 at 18:54
52

The common approach would be to check it with a regular expression like it's also suggested inside the Double.valueOf(String) documentation.

The regexp provided there (or included below) should cover all valid floating point cases, so you don't need to fiddle with it, since you will eventually miss out on some of the finer points.

If you don't want to do that, try catch is still an option.

The regexp suggested by the JavaDoc is included below:

final String Digits     = "(\\p{Digit}+)";
final String HexDigits  = "(\\p{XDigit}+)";
// an exponent is 'e' or 'E' followed by an optionally 
// signed decimal integer.
final String Exp        = "[eE][+-]?"+Digits;
final String fpRegex    =
    ("[\\x00-\\x20]*"+ // Optional leading "whitespace"
    "[+-]?(" +         // Optional sign character
    "NaN|" +           // "NaN" string
    "Infinity|" +      // "Infinity" string

    // A decimal floating-point string representing a finite positive
    // number without a leading sign has at most five basic pieces:
    // Digits . Digits ExponentPart FloatTypeSuffix
    // 
    // Since this method allows integer-only strings as input
    // in addition to strings of floating-point literals, the
    // two sub-patterns below are simplifications of the grammar
    // productions from the Java Language Specification, 2nd 
    // edition, section 3.10.2.

    // Digits ._opt Digits_opt ExponentPart_opt FloatTypeSuffix_opt
    "((("+Digits+"(\\.)?("+Digits+"?)("+Exp+")?)|"+

    // . Digits ExponentPart_opt FloatTypeSuffix_opt
    "(\\.("+Digits+")("+Exp+")?)|"+

    // Hexadecimal strings
    "((" +
    // 0[xX] HexDigits ._opt BinaryExponent FloatTypeSuffix_opt
    "(0[xX]" + HexDigits + "(\\.)?)|" +

    // 0[xX] HexDigits_opt . HexDigits BinaryExponent FloatTypeSuffix_opt
    "(0[xX]" + HexDigits + "?(\\.)" + HexDigits + ")" +

    ")[pP][+-]?" + Digits + "))" +
    "[fFdD]?))" +
    "[\\x00-\\x20]*");// Optional trailing "whitespace"

if (Pattern.matches(fpRegex, myString)){
    Double.valueOf(myString); // Will not throw NumberFormatException
} else {
    // Perform suitable alternative action
}
Sled
  • 18,541
  • 27
  • 119
  • 168
Johannes Wachter
  • 2,715
  • 17
  • 17
  • +1 - Much better than catching an exception (my lame answer...) – Starkey Aug 22 '10 at 22:40
  • how does one do this exactly? – Louis Rhys Aug 22 '10 at 22:40
  • 2
    @Louis Rhys - There is a code example in the documentation link in the answer. – Starkey Aug 22 '10 at 22:44
  • 1
    @Louis Rhys: The complete code you need is provided in behind the link. You just need to copy that into your code and wrap the final if statement around your use of `Double.parseDouble`. But I would put the could into a utility class or method so it's easier reusable in your project. Something like `parseDoubleSafe(String check, Double default)` or something like that. – Johannes Wachter Aug 22 '10 at 22:45
  • 4
    the approach taken by the Java API developer is imbecile: they gives us a chunk of code that every interested person has to copy/paste into a utility method. Why not just providing that method themselves in the `Double` class? :facepalm (endless) – Clint Eastwood Jun 09 '20 at 20:43
12

Something like below should suffice :-

String decimalPattern = "([0-9]*)\\.([0-9]*)";  
String number="20.00";  
boolean match = Pattern.matches(decimalPattern, number);
System.out.println(match); //if true then decimal else not  
CoolBeans
  • 20,654
  • 10
  • 86
  • 101
11

Google's Guava library provides a nice helper method to do this: Doubles.tryParse(String). You use it like Double.parseDouble but it returns null rather than throwing an exception if the string does not parse to a double.

ruhong
  • 1,793
  • 5
  • 28
  • 34
8

All answers are OK, depending on how academic you want to be. If you wish to follow the Java specifications accurately, use the following:

private static final Pattern DOUBLE_PATTERN = Pattern.compile(
    "[\\x00-\\x20]*[+-]?(NaN|Infinity|((((\\p{Digit}+)(\\.)?((\\p{Digit}+)?)" +
    "([eE][+-]?(\\p{Digit}+))?)|(\\.((\\p{Digit}+))([eE][+-]?(\\p{Digit}+))?)|" +
    "(((0[xX](\\p{XDigit}+)(\\.)?)|(0[xX](\\p{XDigit}+)?(\\.)(\\p{XDigit}+)))" +
    "[pP][+-]?(\\p{Digit}+)))[fFdD]?))[\\x00-\\x20]*");

public static boolean isFloat(String s)
{
    return DOUBLE_PATTERN.matcher(s).matches();
}

This code is based on the JavaDocs at Double.

Zach-M
  • 2,127
  • 18
  • 12