1

Though the question is generic, I would mention the scenario which sparked the query.

Scenario:

I am interested in analyzing a large number of strings (numeric ones in particular). Therefore, my first job is to filter out those ones which contain even a single character other than numbers.

A simple way to do this is (in Java):

for (String val : stringArray){
   try{
     int num = Integer.parseInt(val);
     doSomething(num);
   }
   catch(NumberFormatException nfe){}
}

Another point which I must mention is that there are only about 5% of the strings in the array which are purely numeric. Thus there would be, in short, a lot of catching involved.

What I was wondering about was that whether this was an efficient way in terms of design or should I be thinking of other ways to do the same?


Conclusion based on answers: Exceptions are indeed expensive and it is not a very good design practice to use them as a form of control statement. Therefore, one should try and look for alternatives wherever possible and if still exceptions seem to be clearer/easier, one should document it well.

Saurabh Agarwal
  • 507
  • 2
  • 5
  • 16
  • Use a profiler to see what is slowing your program. What you do there is inherently correct as there is no other standard way to text if a string is numeric. – Denys Séguret Jun 15 '12 at 15:32
  • @dystroy: I am not saying that this is slowing the program. It works fine. But my test case is quite small (~1000 strings) but in real time it might involve much more than that. Again, its pure speculation since I don't know how exception handling works in say java, but I guess an exception might have some sort of inheritance trees. So if there is an exception it tries and find which exception was thrown among different classes. Further, throwing exceptions just seems like a harsh way to stop the code flow, doesn't it? (I'm kidding) – Saurabh Agarwal Jun 15 '12 at 15:36
  • 2
    It's a harsh way, yes, but that's how java is made : in many cases (like this one), it's the standard way of branching. – Denys Séguret Jun 15 '12 at 15:38
  • All the guys that say that you should profile first before you employ micro optimizations are very right, but they are missing the point. The problem with this kind of code is not in its (potential)inefficiency, but that it abuses the exception mechanism by controlling program flow with exceptions. It drastically reduces the maintainability of your code in terms of clarity. – Vitaliy Jun 15 '12 at 15:50
  • 1
    Nobody mentioned the term *vexing exception*: http://blogs.msdn.com/b/ericlippert/archive/2008/09/10/vexing-exceptions.aspx . A vexing exception is an exception that you're forced to deal with because a libary author made an unfortunate design decision. Yes, be aware that vexing exceptions suck, but you cna't do much about it. For the most part you should just accept that it sucks and move on. – Evan Harper Jul 11 '13 at 14:02

4 Answers4

2

What you do here is inherently correct as there is no other standard way in java to check if a string is numeric.

If a profiling proves you that this operation is too long, you could try to do it yourself as in the parseInt method but the JVM won't be able to do the same optimizations so I don't recommend it. You'll see that the JVM is heavily optimized to handle exceptions and that it does this job very well.

As a curiosity, here are a few ways to do it in java :

http://rosettacode.org/wiki/Determine_if_a_string_is_numeric#Java

with links to other languages, but your solution is the standard and idiomatic one and I doubt you'll find a big difference by rewriting it as in the example :

private static final boolean isNumeric(final String s) {
  if (s == null || s.isEmpty()) return false;
  for (int x = 0; x < s.length(); x++) {
    final char c = s.charAt(x);
    if (x == 0 && (c == '-')) continue;  // negative
    if ((c >= '0') && (c <= '9')) continue;  // 0 - 9
    return false; // invalid
  }
  return true; // valid
}

Using this, in my opinion, would be a typical case of premature optimization leading to a less maintainable code.

Denys Séguret
  • 372,613
  • 87
  • 782
  • 758
1

It is not efficient. You can look up lots of resources on the web as to why throwing an exception is considered expensive, for example: http://www.yoda.arachsys.com/csharp/exceptions.html.

Unfortunately Java does not come with such a utility method OOTB (like C#'s tryParse). You can enumerate the characters of the string and use the Character.isDigit method (you can even intertwine the verification and the transformation into an int).

Exceptions should be used for abnormal termination of some flow. Performing an operation that might raise an exception, you should always consider whether you can perform a check that will save you the cost and especially the code for handling an exception. For example- check whether a string is a number instead of trying to parse it and relying on the exception mechanism to tell you if its not.

Vitaliy
  • 8,044
  • 7
  • 38
  • 66
0

It's not likely to matter much in the larger context of your application. Micro-optimizations like this are hard to guess at.

A better approach is to write your code as cleanly as possible and then measuring to see what its performance is and where bottlenecks, if any, reside. If you find that your performance is not acceptable, find the biggest bottleneck and address it if you can; rinse and repeat until performance is acceptable.

The problem is that none of us are smart enough to "know" where the problems will be. You're better off optimizing with data instead of guessing.

In your case, that's an unchecked exception. You could ignore it, but that would mean that a single bad string would blow you out of the loop. Putting the catch inside the loop allows you to tolerate that small percentage of input strings that fail the numeric parsing and continue on.

duffymo
  • 305,152
  • 44
  • 369
  • 561
0

A non-exception based way to check for numeric-only strings would be to user a regular expression. For example:

public static void main(String[] args) throws Exception {
    String[] array = {
            "abc",
            "123",
            "12A",
    };
    Pattern p = Pattern.compile("\\d*");
    for (String s: array) {
        Matcher m = p.matcher(s);
        if (m.matches()) {
            System.out.println(s);
        }
    }
}

Exception based handling can be expensive.

Regular expressions are not the fastest either.

Try both and see which is faster for you.

ewan.chalmers
  • 16,145
  • 43
  • 60