views:

223

answers:

8

Hello, Long.parseLong( string ) throws an error if string is not parsable into long. Is there a way to validate the string faster than using try-catch? Thanks

+2  A: 

From commons-lang StringUtils:

public static boolean isNumeric(String str) {
    if (str == null) {
        return false;
    }
    int sz = str.length();
    for (int i = 0; i < sz; i++) {
        if (Character.isDigit(str.charAt(i)) == false) {
            return false;
        }
    }
    return true;
}
lexicore
Thanks, lexicore
Serg
what about negative numbers?
Roman
What about negatives, and values outside Long's limits?
Carl Manaster
Oh guys, how about everything? The method gives a basic clue, or is it not enough?
lexicore
Guys/Gals-if any?!!!! Come on . How come calling another method with `if` condition in a `for` loop ever be "faster" than `try{ Long.parseLong( string ) }catch(Exception e){}` - I think the question as well as this answer deserves a down voting. Do not *over-engineer*
ring bearer
What do you think Long.parseLong(string) does exactly?
lexicore
@ring bearer: +10
Roman
@lexicore - if your question is directed at me, I would say you will end up re-implementing `Long.parseLong()` by refining/robust-ifying the snippet you provided - take no offense. That's all.
ring bearer
@lexicore: No, it's not enough. Because it doesn't correctly handle all possible strings - like `Long.parseLong()` does. The implication of your short function, and suggestions for regexes and the like, is that it can be simply done and would save time. It's not trivially simple, and you would be hard pressed to do better than `Long.parseLong()`. Implying otherwise does a disservice to the OP and other readers.
Carl Manaster
@ring bearer: Long.parseLong() also supports non-decimal radixes. Therefor what I'd end up with would be a bit simpler and faster.However I agree that catching an exception is fully ok here. Was just trying to answer the original question instead of altering it - just for fun.ps. No offense, surely. I'm sorry if my words could seem like assuming that.
lexicore
@ring bearer: and @roman: you guys are nuts. What exactly do you think Long.parseLong does? Did you *look* at that pig? As lexicore is saying, Long.parseLong does crazy stuff, like accepting any radix and checking non-ASCII digits... It is *trivial* to write a method that **OWNS** Long.parseLong to parse ASCII-digits only base 10 longs (see my answer). Been there, done that and I know how Long.parseLong() is implemented (which I guess you never looked at). But the great Java gods came with it, so it must be *the one holy way to do it*, right?
Webinator
@lexicore: don't worry, you're not the only one... It's just that on SO there are really a lot of weird "programmers" all engaging in some kind of "groupthink": freethought is frowned upon here. Don't dare about suggesting something else than a default library, because these programmers uses these default libraries all the time. They couldn't be *writing* them, so they defend them. You can see that pattern on soooo many question on SO it's not even funny. I'll call these "programmers" the *"default-API-kneejerkers"* from now on ;)
Webinator
@WizardOfOdds - Thanks for the knee jerk comment; any average joe can see the source of `parseLong()` using netbeans these days; Me being one has seen it. And what makes you guys think checking non-decimal radix is an issue?
ring bearer
+1  A: 

Have a look here.

Bozhidar Batsov
It would have to be adapted for Long values.
Dave Jarvis
A: 

You could try using a regular expression to check the form of the string before trying to parse it?

Moonshield
Yes, regular expressions are indeed very fast. :)
lexicore
A: 

You could do something like

if(s.matches("\\d*")){
}

Using regular expression - to check if String s is full of digits. But what do you stand to gain? another if condition?

ring bearer
what about negative numbers? or very big numbers which cannot fit in long
Roman
@Roman - I was only trying to give an idea here. Length check and refining of regex can be done. Ex: `s.matches("[+|-]\\d*")` will take care of + or - signs.The whole point of my answer was- why not still use `try/catch` instead of redundant *under-performing* checks?
ring bearer
+1  A: 

I think that's the only way of checking if a String is a valid long value. but you can implement yourself a method to do that, having in mind the biggest long value.

cd1
+5  A: 

You can create rather complex regular expression but it isn't worth that. Using exceptions here is absolutely normal.

It's natural exceptional situation: you assume that there is an integer in the string but indeed there is something else. Exception should be thrown and handled properly.

If you look inside parseLong code, you'll see that there are many different verifications and operations. If you want to do all that stuff before parsing it'll decrease the performance (if we are talking about parsing millions of numbers because otherwise it doesn't matter). So, the only thing you can do if you really need to improve performance by avoiding exceptions is: copy parseLong implementation to your own function and return NaN instead of throwing exceptions in all correspondent cases.

Roman
@Roman: and there lots of usually pointless and needless things, like working in base others than 10 and parsing digits that are non-ASCII. Which is why you can rewrite a parseBase10AsciiDigitsLong(...) that is faster than the default Long.parseLong. But I'm sure every single brainfart from the Java gods cannot be discussed...
Webinator
A: 

There are much faster ways to parse a long than Long.parseLong. If you want to see an example of a method that is not optimized then you should look at parseLong :)

Do you really need to take into account "digits" that are non-ASCII?

Do you really need to make several methods calls passing around a radix even tough you're probably parsing base 10?

:)

Using a regexp is not the way to go: it's harder to determine if you're number is too big for a long: how do you use a regexp to determine that 9223372036854775807 can be parsed to a long but that 9223372036854775907 cannot?

That said, the answer to a really fast long parsing method is a state machine and that no matter if you want to test if it's parseable or to parse it. Simply, it's not a generic state machine accepting complex regexp but a hardcoded one.

I can both write you a method that parses a long and another one that determines if a long can be parsed that totally outperforms Long.parseLong().

Now what do you want? A state testing method? In that case a state testing method may not be desirable if you want to avoid computing twice the long.

Simply wrap your call in a try/catch.

And if you really want something faster than the default Long.parseLong, write one that is tailored to your problem: base 10 if you're base 10, not checking digits outside ASCII (because you're probably not interested in Japanese's itchi-ni-yon-go etc.).

Webinator
In addition to that I may add that in your problem space, it is very unlikely that by some magic the maximum and minimum long you'd need to parse would exactly match -2**63+1 and 2**63 (unless your problem space happens to be the computing space). Which means a custom made state machine can be even better performing than a "normal" parselong, allowing to parse any long from -2**63+1 to 2**63 (and, yup, I've (re)written "parse long" much faster than Long.parseLong and they're in production code on a *lot* of systems ;)
Webinator
A: 

You can use java.util.Scanner

Scanner sc = new Scanner(s);
if (sc.hasNextLong()) {
   long num = sc.nextLong();
}

This does range checking etc, too. Of course it will say that "99 bottles of beer" hasNextLong(), so if you want to make sure that it only has a long you'd have to do extra checks.

polygenelubricants