Which one of the following is a better practice to check if a string is float?
try{
Double.parseDouble(strVal);
}catch(NumberFormatException e){
//My Logic
The first one is going to perform better than the regex when the string matches the double. For one it's very fast to parse it when the recognizer is hard coded as it would be with Double.parse. Also there's nothing to maintain it's whatever Java defines as the Double is as a string. Not to mention Double.parseDouble() is easier to read.
The other solution isn't going to be compiled so the first thing that the regex has to do is compile and parse the regex expression, then it has to run that expression, then you'll have to execute Double.parseDouble() to get it into a double. And that's going to be done for every number passed to it. You might be able to optimize it with Pattern.compile(), but executing the expression is going to be slower. Especially when you have to run a Double.doubleParse to get the value into a double.
Yes exceptions are not super fast, but you'll only have to pay that price when you parse an error. If you don't plan on seeing lots of errors then I don't think you'll notice the slow down from gathering the stacktrace on the throw (which is why exceptions perform poorly). If you're only going to encounter a handful of exceptions then performance isn't going be a problem. The problem is you expected a double and it wasn't so probably some configuration mistake so tell the user and quit, or pick a suitable default and continue. That's all you can do in those cases.
And yeah, I would like to know which one is good coding practice?
Either can be good coding practice, depending on the context.
If bad numbers are unlikely (i.e. it is an "exceptional" situation), then the exception-based solution is fine. (Indeed, if the probability of bad numbers is small enough, exceptions might even be faster on average. It depends on the relative speed of Double.parseDouble()
and a compiled regex for typical input strings. That would need to be measured ...)
If bad numbers are reasonably (or very) likely (i.e. it is NOT an "exceptional" situation), then the regex-based solution is probably better.
If the code path that does the test is infrequently executed, then it really makes no difference which approach you use.
May be you can also try this way.But this is generic for a string containing valid number.
public static boolean isNumeric(String str)
{
str = "2.3452342323423424E8";
// str = "21414124.12412412412412";
// str = "123123";
NumberFormat formatter = NumberFormat.getInstance();
ParsePosition pos = new ParsePosition(0);
formatter.parse(str, pos);
return str.length() == pos.getIndex();
}
If you use parseDouble
, you will end up with what Mark said, but in a more readable way, and might profit from performance improvements and bug fixes.
Since exceptions are only costly when they are thrown, there is only need to look for a different strategy if you
In the end you will call parseDouble either, and therefore it is considered alright to use it that way.
Note that your pattern rejects 7. as a Double, while Java and C/C++ don't, as well as scientific notation like 4.2e8
.
Personal opinion - of the code I've seen, I would expect that most developers would tend towards the try - catch blocks. The try catch is in a sense also more readable and makes the assumption that for most cases the string will contain a valid number. But there are a number of things to consider with you examples which may effect which you choose.
Below is performance test to see the performance difference between regular expression VS try catch for validating a string is numeric.
Below table shows stats with a list(100k) with three points (90%, 70%, 50%) good data(float value) and remaining bad data(strings).
**90% - 10% 70% - 30% 50% - 50%**
**Try Catch** 87234580 122297750 143470144
**Regular Expression** 202700266 192596610 162166308
Performance of try catch is better (unless the bad data is over 50%) even though try/catch may have some impact on performance. The performance impact of try catch is because try/catch prevents JVM from doing some optimizations. Joshua Bloch, in "Effective Java," said the following:. Joshua Bloch, in "Effective Java," said the following:
• Placing code inside a try-catch block inhibits certain optimizations that modern JVM implementations might otherwise perform.
public class PerformanceStats {
static final String regularExpr = "([0-9]*[.])?[0-9]+";
public static void main(String[] args) {
PerformanceStats ps = new PerformanceStats();
ps.statsFinder();
//System.out.println("123".matches(regularExpr));
}
private void statsFinder() {
int count = 200000;
int ncount = 200000;
ArrayList<String> ar = getList(count, ncount);
System.out.println("count = " + count + " ncount = " + ncount);
long t1 = System.nanoTime();
validateWithCatch(ar);
long t2 = System.nanoTime();
validateWithRegularExpression(ar);
long t3 = System.nanoTime();
System.out.println("time taken with Exception " + (t2 - t1) );
System.out.println("time taken with Regular Expression " + (t3 - t2) );
}
private ArrayList<String> getList(int count, int noiseCount) {
Random rand = new Random();
ArrayList<String> list = new ArrayList<String>();
for (int i = 0; i < count; i++) {
list.add((String) ("" + Math.abs(rand.nextFloat())));
}
// adding noise
for (int i = 0; i < (noiseCount); i++) {
list.add((String) ("sdss" + rand.nextInt() ));
}
return list;
}
private void validateWithRegularExpression(ArrayList<String> list) {
ArrayList<Float> ar = new ArrayList<>();
for (String s : list) {
if (s.matches(regularExpr)) {
ar.add(Float.parseFloat(s));
}
}
System.out.println("the size is in regular expression " + ar.size());
}
private void validateWithCatch(ArrayList<String> list) {
ArrayList<Float> ar = new ArrayList<>();
for (String s : list) {
try {
float e = Float.parseFloat(s);
ar.add(e);
} catch (Exception e) {
}
}
System.out.println("the size is in catch block " + ar.size());
}
}