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.
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.
You can always wrap Double.parseDouble() in a try catch block.
try
{
Double.parseDouble(number);
}
catch(NumberFormatException e)
{
// not a double
}
I don't want to parse a string to a double, I want to know if whatever is contained in the string is in the format of a double. For instance, if I have a string that says "10", I want to have a boolean or something that returns false. If I have a string that says "10.5", then I want the boolean to say true. Also, I don't want to create a new method to do this.
I don't like the throwing and catching of Exceptions
This can be made much cleaner with the use of a Scanner. It might not be the most performant way, but it's fast and easy to use.
try (Scanner scanner = new Scanner(x)) {
if (scanner.hasNextInt()) doFoo(scanner.nextInt());
else if (scanner.hasNextDouble()) doFoo(scanner.nextDouble());
else doFoo(x);
}
However, if this is going to be called hundreds of thousands of times, the try catch method might be faster, though you should encapsulate those into their own functions. You'd need to profile to be sure which is faster, but I believe it would be this because Scanner.hasNextFoo uses regular expressions:
public static boolean isInteger(String str) {
try {
Integer.parse(str);
return true;
} catch (NumberFormatException e) {
return false;
}
}
Also, your function is doing multiple things: printing/reporting, and parsing/forwarding to doFoo. This is not a good thing. I'd recommend removing those and handling them where it's more appropriate:
public static void testString(String val) {
String x = val.trim();
try (Scanner scanner = new Scanner(x)) {
if (scanner.hasNextInt()) doFoo(scanner.nextInt());
else if (scanner.hasNextDouble()) doFoo(scanner.nextDouble());
else doFoo(x);
}
}
That was much shorter. Now if you wanted the same functionality, it would look like so:
public static void testTestString(String val) {
System.out.print("Original '" + val + "' ");
testString(val);
}
// ...
public static void doFoo(int i) {
System.out.println("It's an integer: " + i);
// ...
}
If you want your code to be extremely extensible, there is another way. Notice how the new function I suggested still does multiple things:
- It detects the type of the string
- It parses the value from the string
- It forwards the value on to another function
We can separate these into their own components.
This is only really worth it if you can foresee adding types to be a common feature, but especially if the "another function" you forward to should be selectable by the user (say, if you packaged these functions as member functions of an object):
// Class is the easiest type we can return
private static Class<?> determineType(String val) {
try (Scanner scanner = new Scanner(val)) {
if (scanner.hasNextInt()) return Integer.class;
if (scanner.hasNextDouble()) return Double.class;
return String.class;
}
}
private static final Map<Class<?>, Function<String, ?>> parsers = new IdentityHashMap<>();
private static final Map<Class<?>, Consumer<Object>> functionSwitch = new IdentityHashMap<>();
static {
parsers.put(Integer.class, Integer::parseInt);
parsers.put(Double.class, Double::parseDouble);
parsers.put(String.class, Function.identity());
// Note that, due to limitations in the type system,
// i is of type Object, so we need to cast it to the appropriate
// class before forwarding on to the function.
functionSwitch.put(Integer.class, i -> doFoo((Integer) i));
functionSwitch.put(Double.class, d -> doFoo((Double) d));
functionSwitch.put(String.class, str -> doFoo((String) str));
}
public static void testString(String val) {
val = val.trim(); // This could even be part of the parser's responsibility
Class<?> stringType = determineType(val);
Function<String, ?> parser = parsers.get(stringType);
functionSwitch.get(stringType).accept(parser.apply(val));
}
Background
This question was brought to my attention in The 2nd Monitor chat room because in the past I have claimed that using exception handling to handle parse exceptions is "a bad idea and slow". This is exactly what your code is doing, and it's a bad idea, and slow.... at least, that's what I thought, until I benchmarked your code.
Now, in the past, I wrote a CSV parser and it used a similar system to yours to handle the values in a field, and I discovered that I got a significant speed-up (like 100% faster) when I prevalidated the values to an large extent, before doing a parseInt or parseDouble on them. I found that it is much better to "identify" a value of a certain type to a high degree of confidence, and thus reduce the number of exceptions thrown.
In your code, if the values are 1/3 integers, 1/3 double, and 1/3 string, then on average you are creating 1 exception for each value (none for ints, 1 for doubles, and 2 for strings). Worst case, if all your values are strings, you'll create 2 exceptions per value.
What if you could (almost) guarantee that all your parseInt and parseDouble calls will succeed, and you'll have (almost) no exceptions? Is the work to check the value "worth it"?
My claim is yes, it's worth it.
So, I have tried to prove it, and ... the results are interesting.
I used my MicroBench performance system to run the benchmark, and I built a dummy "load" for the doFoo function. Let's look at my test-rig:
public class ParseVal {
private final LongAdder intsums = new LongAdder();
private final DoubleAdder doubsums = new DoubleAdder();
private final LongAdder stringsums = new LongAdder();
private final void doFoo(int val) {
intsums.add(val);
}
private final void doFoo(double val) {
doubsums.add(val);
}
private final void doFoo(String val) {
stringsums.add(val.length());
}
@Override
public String toString() {
return String.format("IntSum %d - DoubleSum %.9f - StringLen %d", intsums.longValue(), doubsums.doubleValue(), stringsums.longValue());
}
public static final String testFunction(BiConsumer<ParseVal, String> fn, String[] data) {
ParseVal pv = new ParseVal();
for (String v : data) {
fn.accept(pv, v);
}
return pv.toString();
}
public static final String[] testData(int count) {
String[] data = new String[count];
Random rand = new Random(count);
for (int i = 0; i < count; i++) {
String base = String.valueOf(1000000000 - rand.nextInt(2000000000));
switch(i % 3) {
case 0:
break;
case 1:
base += "." + rand.nextInt(10000);
break;
case 2:
base += "foobar";
break;
}
data[i] = base;
}
return data;
}
.......
public void testStringOP(String val) {
String x = val.trim();
try {
int i = Integer.parseInt(x);
doFoo(i);
} catch (NumberFormatException e) {
try {
double d = Double.parseDouble(x);
doFoo(d);
} catch (NumberFormatException e2) {
doFoo(x);
}
}
}
public static void main(String[] args) {
String[] data = testData(1000);
String expect = testFunction((pv, v) -> pv.testStringOP(v), data);
System.out.println(expect);
....
}
}
The doFoo methods have an accumulator mechanism (adding up ints, doubles, and the string lengths) and making the results available in a toString method.
Also, I have put your function in there as testStringOP.
There is a testData function which builds an array if input strings where there are approximately equal numbers of int, double, and string values.
Finally, the benchmark function:
public static final String testFunction(BiConsumer<ParseVal, String> fn, String[] data) {
ParseVal pv = new ParseVal();
for (String v : data) {
fn.accept(pv, v);
}
return pv.toString();
}
That function takes an input function and the test data as an argument, and returns the String summary as a result. You would use this function like it's used in the main method....
String expect = testFunction((pv, v) -> pv.testStringOP(v), data);
which runs the testStringOP function on all the input data values, and returns the accumulated string results.
What's nice is that I can now create other functions to test performance, for example testStringMyFn and call:
String myresult = testFunction((pv, v) -> pv.testStringMyFn(v), data);
This is the basic tool I can use for the MicroBench system: https://github.com/rolfl/MicroBench
Scanner option
Let's start by comparing your function to the Scanner type system recommended in another answer... Here's the code I used for the Scanner:
public void testStringScanner(String val) {
val = val.trim();
try (Scanner scanner = new Scanner(val)) {
if (scanner.hasNextInt()) {
doFoo(scanner.nextInt());
} else if (scanner.hasNextDouble()) {
doFoo(scanner.nextDouble());
} else {
doFoo(val);
}
}
}
and here's how I benchmarked that code:
public static void main(String[] args) {
String[] data = testData(1000);
String expect = testFunction((pv, v) -> pv.testStringOP(v), data);
System.out.println(expect);
UBench bench = new UBench("IntDoubleString Parser")
.addTask("OP", () -> testFunction((pv, v) -> pv.testStringOP(v), data), s -> expect.equals(s))
.addTask("Scanner", () -> testFunction((pv, v) -> pv.testStringScanner(v), data), s -> expect.equals(s));
bench.press(10).report("Warmup");
bench.press(100).report("Final");
}
That runs the benchmark on both your function, and the Scanner function, and does a warmup run (to get JIT optimzations done), and a "Final" run to get real results.... what are the results, you ask?
Task IntDoubleString Parser -> OP: (Unit: MILLISECONDS) Count : 100 Average : 1.6914 Fastest : 1.5331 Slowest : 3.2561 95Pctile : 2.0277 99Pctile : 3.2561 TimeBlock : 1.794 2.037 1.674 1.654 1.674 1.588 1.665 1.588 1.634 1.606 Histogram : 99 1 Task IntDoubleString Parser -> Scanner: (Unit: MILLISECONDS) Count : 100 Average : 69.9713 Fastest : 67.2338 Slowest : 98.4322 95Pctile : 73.8073 99Pctile : 98.4322 TimeBlock : 77.028 70.050 69.325 69.860 69.094 68.498 68.547 68.779 69.586 68.945 Histogram : 100
What does that mean? It means, on average, your code is 40-times faster than the Scanner. Your code runs in 1.7Milliseconds to process 1000 input values, and the scanner runs in 70 milliseconds.
So, a Scanner is a bad idea if performance is required, right? I agree.
Alternative
But, what about a RegEx pre-validation check? Note that the regex will not guarantee a clean parse, but it can go a long way. For example, the regex [+-]?\d+ will match any integer, right, but is -999999999999999999999 a valid integer? No, it's too big. But, it is a valid double. We will still need to have a try/catch block even if we pass the regex prevalidation. That's going to eliminate almost all exceptions, though....
So, what do we do to prevalidate things? Well, the Double.valueOf(String) function documents a regex for matching double values in Strings. It's complicated, and I made a few modifications because we don't have already trimmed our inputs, but here's a couple of patterns for prevalidating double values, and integer values:
private static final String Digits = "(\\p{Digit}+)";
private static final String HexDigits = "(\\p{XDigit}+)";
private static final String Exp = "[eE][+-]?"+Digits;
private static final String fpRegex =
( //"[\\x00-\\x20]*"+ // Optional leading "whitespace"
"[+-]?(" + // Optional sign character
"NaN|" + // "NaN" string
"Infinity|" + // "Infinity" string
"((("+Digits+"(\\.)?("+Digits+"?)("+Exp+")?)|"+
"(\\.("+Digits+")("+Exp+")?)|"+
"((" +
"(0[xX]" + HexDigits + "(\\.)?)|" +
"(0[xX]" + HexDigits + "?(\\.)" + HexDigits + ")" +
")[pP][+-]?" + Digits + "))" +
"[fFdD]?))"); // +
//"[\\x00-\\x20]*");// Optional trailing "whitespace"
Pattern isDouble = Pattern.compile(fpRegex);
Pattern isInteger = Pattern.compile("[+-]?[0-9]+");
We can use those functions to build the code:
public void testStringRegex(String val) {
String x = val.trim();
if (isInteger.matcher(x).matches()) {
try {
doFoo(Integer.parseInt(x));
} catch (NumberFormatException nfe) {
try {
doFoo(Double.parseDouble(x));
} catch (NumberFormatException e) {
doFoo(x);
}
}
} else if (isDouble.matcher(x).matches()) {
try {
doFoo(Double.parseDouble(x));
} catch (NumberFormatException e) {
doFoo(x);
}
} else {
doFoo(x);
}
}
Now, that's pretty complicated, right? Well, it does a "quick" integer regex check, and if it's likely an integer, it tries to parse it as an integer, and fails over to a double, and then to a string....
If it's not likely an integer, it checks if it's a double, and so on.....
How can this code be faster, you ask? Well, we're almost certainly having clean parses when we do them, and we'll have almost no exceptions... But, is it actually faster?
Here are the results:
Task IntDoubleString Parser -> OP: (Unit: MILLISECONDS) Count : 100 Average : 1.6689 Fastest : 1.5580 Slowest : 2.1572 95Pctile : 1.8012 99Pctile : 2.1572 TimeBlock : 1.695 1.752 1.709 1.670 1.641 1.648 1.643 1.639 1.662 1.630 Histogram : 100 Task IntDoubleString Parser -> Regex: (Unit: MILLISECONDS) Count : 100 Average : 1.9580 Fastest : 1.8379 Slowest : 2.5713 95Pctile : 2.1004 99Pctile : 2.5713 TimeBlock : 1.978 2.022 1.949 1.966 2.020 1.933 1.890 1.940 1.955 1.928 Histogram : 100 Task IntDoubleString Parser -> Scanner: (Unit: MILLISECONDS) Count : 100 Average : 69.8886 Fastest : 67.1848 Slowest : 77.2769 95Pctile : 71.9153 99Pctile : 77.2769 TimeBlock : 70.940 69.735 69.879 69.381 69.579 69.180 69.611 70.412 70.123 70.045 Histogram : 100
If you look, you'll see the regex version is Slower than the exception version... it runs in 1.95ms but the exception version runs in 1.67ms
Exceptions
But, there's a catch. In these tests, the stack trace for the exceptions is really small... and the "cost" of an exception depends on the depth of the trace, so let's increase the stack depths for the regex and exception code. Well add a recursive function to simulate a deeper stack:
public void testStringDeepOP(String val, int depth) {
if (depth <= 0) {
testStringOP(val);
} else {
testStringDeepOP(val, depth - 1);
}
}
public void testStringDeepRegex(String val, int depth) {
if (depth <= 0) {
testStringRegex(val);
} else {
testStringDeepRegex(val, depth - 1);
}
}
and we will test the OP and Regex code a different "depths" of nesting, 5, 10, and 20 layers deep. The benchmark code is:
UBench bench = new UBench("IntDoubleString Parser")
.addTask("OP", () -> testFunction((pv, v) -> pv.testStringOP(v), data), s -> expect.equals(s))
.addTask("OP D5", () -> testFunction((pv, v) -> pv.testStringDeepOP(v, 5), data), s -> expect.equals(s))
.addTask("OP D10", () -> testFunction((pv, v) -> pv.testStringDeepOP(v, 10), data), s -> expect.equals(s))
.addTask("OP D20", () -> testFunction((pv, v) -> pv.testStringDeepOP(v, 20), data), s -> expect.equals(s))
.addTask("Regex", () -> testFunction((pv, v) -> pv.testStringRegex(v), data), s -> expect.equals(s))
.addTask("Regex D5", () -> testFunction((pv, v) -> pv.testStringDeepRegex(v, 5), data), s -> expect.equals(s))
.addTask("Regex D10", () -> testFunction((pv, v) -> pv.testStringDeepRegex(v, 10), data), s -> expect.equals(s))
.addTask("Regex D20", () -> testFunction((pv, v) -> pv.testStringDeepRegex(v, 20), data), s -> expect.equals(s))
.addTask("Scanner", () -> testFunction((pv, v) -> pv.testStringScanner(v), data), s -> expect.equals(s));
bench.press(10).report("Warmup");
bench.press(100).report("Final");
What are the results?
Final ===== Task IntDoubleString Parser -> OP: (Unit: MILLISECONDS) Count : 100 Average : 1.7005 Fastest : 1.5260 Slowest : 3.9813 95Pctile : 1.9346 99Pctile : 3.9813 TimeBlock : 1.682 1.624 1.612 1.675 1.708 1.658 1.727 1.738 1.672 1.910 Histogram : 99 1 Task IntDoubleString Parser -> OP D5: (Unit: MILLISECONDS) Count : 100 Average : 1.9288 Fastest : 1.7325 Slowest : 4.9673 95Pctile : 2.0897 99Pctile : 4.9673 TimeBlock : 2.124 1.812 1.828 1.873 1.925 1.877 1.855 1.869 1.903 2.221 Histogram : 98 2 Task IntDoubleString Parser -> OP D10: (Unit: MILLISECONDS) Count : 100 Average : 2.2271 Fastest : 2.0171 Slowest : 4.7395 95Pctile : 2.4904 99Pctile : 4.7395 TimeBlock : 2.392 2.125 2.129 2.152 2.246 2.169 2.189 2.203 2.247 2.420 Histogram : 98 2 Task IntDoubleString Parser -> OP D20: (Unit: MILLISECONDS) Count : 100 Average : 2.9278 Fastest : 2.6838 Slowest : 6.3169 95Pctile : 3.2415 99Pctile : 6.3169 TimeBlock : 2.870 2.822 2.860 2.794 2.956 2.861 3.041 3.012 2.853 3.211 Histogram : 99 1 Task IntDoubleString Parser -> Regex: (Unit: MILLISECONDS) Count : 100 Average : 2.0739 Fastest : 1.9338 Slowest : 3.8368 95Pctile : 2.2744 99Pctile : 3.8368 TimeBlock : 2.229 2.083 2.034 2.013 2.021 2.004 2.013 2.096 2.059 2.186 Histogram : 100 Task IntDoubleString Parser -> Regex D5: (Unit: MILLISECONDS) Count : 100 Average : 2.0565 Fastest : 1.9377 Slowest : 3.2857 95Pctile : 2.2646 99Pctile : 3.2857 TimeBlock : 2.148 2.075 2.035 2.038 2.035 2.031 2.026 2.000 2.032 2.145 Histogram : 100 Task IntDoubleString Parser -> Regex D10: (Unit: MILLISECONDS) Count : 100 Average : 2.0647 Fastest : 1.9598 Slowest : 2.6360 95Pctile : 2.2906 99Pctile : 2.6360 TimeBlock : 2.073 2.094 2.051 2.048 2.072 2.029 2.057 2.124 2.057 2.042 Histogram : 100 Task IntDoubleString Parser -> Regex D20: (Unit: MILLISECONDS) Count : 100 Average : 2.0891 Fastest : 1.9930 Slowest : 2.6483 95Pctile : 2.2587 99Pctile : 2.6483 TimeBlock : 2.108 2.070 2.078 2.066 2.071 2.091 2.048 2.090 2.137 2.132 Histogram : 100 Task IntDoubleString Parser -> Scanner: (Unit: MILLISECONDS) Count : 100 Average : 71.7199 Fastest : 67.9621 Slowest : 152.0714 95Pctile : 75.2141 99Pctile : 152.0714 TimeBlock : 71.006 69.896 70.160 69.734 70.824 69.854 71.473 71.888 73.607 78.756 Histogram : 99 1
Here it is expressed as a table (using the average times):
0 5 10 20 OP 1.7005 1.9288 2.2271 2.9278 RegEx 2.0739 2.0565 2.0647 2.0891
Conclusion
So, that's the real problem with exceptions, the performance is unpredictable... and, for example, if you run it inside a Tomcat container, with stacks hundreds of levels deep, you may find this completely destroys your performance.
boolean isDouble(String str) {
try {
Double.parseDouble(str);
return true;
} catch (NumberFormatException e) {
return false;
}
}
There is a note about this in the source for Double:
[...] To avoid calling this method on a invalid string and having a
NumberFormatExceptionbe thrown, the regular expression below can be used to screen the input string: [...]
The final form of the regular expressions that follows is quite long:
[\x00-\x20]*[+-]?(NaN|Infinity|((((\p{Digit}+)(\.)?((\p{Digit}+)?)([eE][+-]?(\p{Digit}+))?)|(\.((\p{Digit}+))([eE][+-]?(\p{Digit}+))?)|(((0xX(\.)?)|(0xX?(\.)(\p{XDigit}+)))[pP][+-]?(\p{Digit}+)))[fFdD]?))[\x00-\x20]*
Using this method however, you can easily exclude some special doubles such as Infinity and NaN which are both accepted by Double.parseDouble. For example like this:
String regExp = "[\\x00-\\x20]*[+-]?(((((\\p{Digit}+)(\\.)?((\\p{Digit}+)?)([eE][+-]?(\\p{Digit}+))?)|(\\.((\\p{Digit}+))([eE][+-]?(\\p{Digit}+))?)|(((0xX(\\.)?)|(0xX?(\\.)(\\p{XDigit}+)))[pP][+-]?(\\p{Digit}+)))[fFdD]?))[\\x00-\\x20]*";
boolean matches = yourString.matches(regExp);
You can check it using the same regular expression the Double class uses. It's well documented here:
http://docs.oracle.com/javase/6/docs/api/java/lang/Double.html#valueOf%28java.lang.String%29
Here is the code part:
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 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
}
There is a handy NumberUtils#isNumber in Apache Commons Lang. It is a bit far fetched:
Valid numbers include hexadecimal marked with the 0x qualifier, scientific notation and numbers marked with a type qualifier (e.g. 123L).
but I guess it might be faster than regular expressions or throwing and catching an exception.
One simple fix is to read the entire line / user input as a String. Something like this should work. (Untested code) :
String s=null;
boolean validInput=false;
do{
s= scannerInstance.nextLine();
if(s.matches("\\d+")){// checks if input only contains digits
validInput=true;
}
else{
// invalid input
}
}while(!validInput);
You can also use Integer.parseInt and then check that integer for non negativity. You can catch NumberFormatException if the input is string or a double.
Scanner scan = new Scanner(System.in);
try {
String s = scan.nextLine();
int x = Integer.parseInt(s);
}
catch(NumberFormatException ex)
{
}
You could write a function to test it by calling Double.parseDouble(String) and catching the NumberFormatException (this will handle double and int values) when it isn't like
public static boolean isNumber(String str) {
try {
double v = Double.parseDouble(str);
return true;
} catch (NumberFormatException nfe) {
}
return false;
}
Then you could call it like
if (isNumber(tokens[2])) {
System.out.println(" Invalid make");
}
And the printf with String might look like,
String msg = "Invalid make";
System.out.printf(" %s%n", msg);
public static boolean isInteger(String s) {
try {
Integer.parseInt(s);
} catch(NumberFormatException e) {
return false;
}
// only got here if we didn't return false
return true;
}
public static boolean isInteger(String s) {
return isInteger(s);
}
and for double too..
Use the Pattern and Matcher classes:
public static final Pattern DOUBLE = Pattern.compile("\\d");
...
if (DOUBLE.matcher(string[i]).find()) {
...
}
This expression
"\\d+\\.\\d+([eE]\\d+)?"
allows 1.1 or 1.1e1 or 1.1E1 formats.
Note that Java allows more eg 1. or 1. or 0x1p1
Use a try catch statement for Double.parseDouble()
try{
double num = Double.parseDouble(value);
System.out.println("is a double");
catch (Exception e){
System.out.println("not a double");
}
You can check that by trying to parse the string with Double.parseDouble() and catching a NumberFormatException. If it doesn't throw this exception, it's a valid double. This code:
private static boolean isDouble(String string)
{
try
{
Double.parseDouble(string);
}
catch (NumberFormatException e)
{
return false;
}
return true;
}
public static void main(String[] args)
{
String maybeDouble0 = "123.4";
String maybeDouble1 = "not a double 345";
String maybeDouble2 = "45";
String maybeDouble3 = "321.";
String maybeDouble4 = ".753";
String maybeDouble5 = "just text";
System.out.println(maybeDouble0 + ": " + isDouble(maybeDouble0));
System.out.println(maybeDouble1 + ": " + isDouble(maybeDouble1));
System.out.println(maybeDouble2 + ": " + isDouble(maybeDouble2));
System.out.println(maybeDouble3 + ": " + isDouble(maybeDouble3));
System.out.println(maybeDouble4 + ": " + isDouble(maybeDouble4));
System.out.println(maybeDouble5 + ": " + isDouble(maybeDouble5));
}
will result in this output:
123.4: true
not a double 345: false
45: true
321.: true
.753: true
just text: false
I prefer this method over a RegEx pattern because it's asking Java directly, instead of assuming to know Java's internal double representations.
Java specifies a regular expression that can be used to validate strings being passed to Double.parseDouble or Double.valueOf in the Javadoc of Double.valueOf:
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
}
If (as the title suggests) you are testing that a String equals a particular double, the simplest and fastest way is to convert the double to a String and then compare:
if (Double.toString(d).equals(s))
rather than dealing with the vagaries and exceptions of parsing a string.
If as your code suggests, you are testing if a String could be parsed (as any double), the code you have now is probably the best way to go. Parsing floating point numbers is quite complex and the work must be done somewhere - might as well let the API do the work. Also, throwing an exception is not that expensive.
Only seek to optimize for performance if your current working implementation is proven to be too slow to be tolerable. Unless you are parsing hundreds of these per second, I wouldn't worry.
Why don't you try Long.valueOf(String) to first parse it as a Long, and failing that parse it as a Double with Double.valueOf(String)?
Both throw a NumberFormatException if the string cannot be parsed.
public static void main(String[] args) throws Exception {
final String s1 = "1234567890";
System.out.println(isParsableAsLong(s1)); // true
System.out.println(isParsableAsDouble(s1)); // true
final String s2 = "1234.56789";
System.out.println(isParsableAsLong(s2)); // false
System.out.println(isParsableAsDouble(s2)); // true
}
private static boolean isParsableAsLong(final String s) {
try {
Long.valueOf(s);
return true;
} catch (NumberFormatException numberFormatException) {
return false;
}
}
private static boolean isParsableAsDouble(final String s) {
try {
Double.valueOf(s);
return true;
} catch (NumberFormatException numberFormatException) {
return false;
}
}
If . can be used to differentiate then:
String number = "12345";
if(number.indexOf(".")>=0){
//decimal
Double doubleValue = Double.valueOf(number);
}else{
Long longValue = Long.valueOf(number);
}
With Exception Handling:
String number = "12345";
//You may define two variables as Double & Long (as used in previous example)
Number formattedNumber = null;
try{
if(number.indexOf(".")>=0){
//decimal
formattedNumber = Double.valueOf(number);
}else{
formattedNumber = Long.valueOf(number);
}
}catch(NumberFormatException nfe){
System.out.println("Not a double or Long");
}
You can parse the value and catch the exception for example, may be you can try like this
try{
Double.valueOf("asdasd");
}
catch (Exception ex){
System.out.println("Not a valid double value");
}
it returns Not a valid double value
Wrapper class Double could be helpful though. You can do something like this:
try{
if(radius instanceof Double)
System.out.println(radius);
}
catch (Exception ex){
System.out.println("error");
}
radius has to be declared as Double.
PS: instanceof won't work with double, it is a primitive datatype.
Scanner sc = new Scanner(System.in);
double radius;
while (true) {
System.out.println("Input Radius:");
try {
inputt = Double.parseDouble(sc.next());
break;
} catch (NumberFormatException ignore) {
System.out.println("Please enter a number.");
}
}
Only break the while loop if user inputs a number/double.