1

I know that easily I can use a try/catch to check command line arguments are a double.

I'm seeking a way to check this without using a costly try/catch block. I'm fairly new to Java. I'ved searched a few forums but haven't found anything specific to my issue.

System.out.println(Double.parseDouble(args[1]));

^^This will cause an error. besides putting this in a try/catch can someone point me towards data validation that will prevent this? assume args[1] is a string of text.

Ravenous
  • 356
  • 1
  • 4
  • 16
  • 3
    Just use a `try/catch NumberFormatException`. Is not _that_ costly (who told you that?) and besides, the validation rules for determining what's a valid `double` value can be quite complex to implement – Óscar López Sep 23 '13 at 15:06
  • http://stackoverflow.com/questions/1102891/how-to-check-a-string-is-a-numeric-type-in-java – Habib Sep 23 '13 at 15:06
  • Related: http://stackoverflow.com/q/8362027/1065197 – Luiggi Mendoza Sep 23 '13 at 15:06
  • How many times do you run that statement? Is it a proven bottleneck? If not, then you should definitely go with the tested and true try/catch solution. Remember: premature optimization is the root of all evil. – ppeterka Sep 23 '13 at 15:07
  • Use try/catch like everybody else. – Tulains Córdova Sep 23 '13 at 15:14
  • I've worked on a project where the try/catch approach was the bottleneck, so this kind of things happen for real and filter out things that were not floats beforehand definitely helped. But here we are talking about command line arguments, you will not have thousands of them, so there is no point in optimizing. Just wrap the try/catch approach in a single method and you'll be fine. – Cyrille Ka Sep 23 '13 at 16:05

4 Answers4

5

The try-catch approach is the generally accepted way to do this, primarily because there are actually a lot of formats a valid double can have:

double a = 42.e10;  // or 42.E10
double b = 42.f;    // or 42.F
double c = 42.d;    // or 42.D
double d = 010E010D;
double e = 0x1.fffffffffffffP+1023;
double f = 0x1.0p-1022;

All of these are valid doubles and can be parsed from a string via parseDouble(). Double.parseDouble("NaN") and Double.parseDouble("Infinity") are also valid (although NaN and Infinity aren't literals). Not to mention parseDouble() also deals with leading or trailing whitespaces. So my answer is: don't! Use the try-catch approach. It is possible to construct a regex that matches some subset of (or maybe even all) valid double formats, but I doubt that will actually be more efficient than catching and handling a NumberFormatException.


A full regex is actually explained in the documentation of valueOf():

To avoid calling this method on an invalid string and having a NumberFormatException be thrown, the regular expression below can be used to screen the input string:

  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 section 3.10.2 of
       // The Java™ Language Specification.

       // 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
  }

As you can see it's somewhat of a nasty regex.

arshajii
  • 127,459
  • 24
  • 238
  • 287
  • Thanks for the responses. I was really just looking on how it would work to validate without using the try/catch. More for informational knowledge rather than implementation. – Ravenous Sep 30 '13 at 14:55
  • @user2807730 Well the regex is the only other sane approach I can think of. In any case, don't forget to [accept an answer](http://meta.stackexchange.com/questions/5234/how-does-accepting-an-answer-work/5235#5235) if any worked for you. – arshajii Sep 30 '13 at 14:56
  • if (args[1].hasNextDouble()){ System.out.println(Double.parseDouble(args[1])); } ^^Will this not work? I wonder because no one suggested it. – Ravenous Oct 07 '13 at 14:09
  • @user2807730 No (assuming `args` is a string array) because strings don't have a `hasNextDouble()` method. – arshajii Oct 07 '13 at 16:18
1

As commenter Óscar López says, just use a try/catch block and catch NumberFormatException. This is the right way to ensure that the target string is a properly formatted double and the potential overhead of the try/catch construct is worth the correctness and clarity of the program.

Double d = null;
try {
  d = Double.parseDouble(args[1]);
} catch (NumberFormatException nfe) {
  // TODO
}
maerics
  • 151,642
  • 46
  • 269
  • 291
1

Java has no method like isDouble or isNumeric out of the box, But you could write them on your own:

public static boolean isDouble(String s) {
    try {
        Double.parseDouble(s);
    } catch (NumberFormatException e) {
        return false;
    }
    return true;
}

But double has many ways to be writen it:

  • 23.2
  • 23f
  • 23e10
  • 2_3.4_5 (cannot be parsed with Double#parseDouble(String))
  • 2_3E1_0d (cannot be parsed with Double#parseDouble(String))

If you just want to check for the XX.XXX pattern this is the way to go using RegEx:

public static boolean isDoubleDigits(String s) {
    return s.matches("\\d+(\\.\\d{1,2})?");
}
Philipp Sander
  • 10,139
  • 6
  • 45
  • 78
  • 1
    The `_`s actually don't work with `parseDouble()`, even though they are valid in a double literal as of Java 7. – arshajii Sep 23 '13 at 15:34
0

Why not use a framework for command-line input validation? Checkout Apache Commons CLI project

nadirsaghar
  • 557
  • 1
  • 4
  • 20