12

Apache's StringUtils.isNumeric() method specification says:
Checks if the String contains only unicode digits. A decimal point is not a unicode digit and returns false. Null will return false. An empty String ("") will return true.

Is this logically right? Why do they see empty string as numeric?

skaffman
  • 398,947
  • 96
  • 818
  • 769
Andriy Sholokh
  • 852
  • 2
  • 6
  • 15

6 Answers6

14

The behavior changed in 3.0. From What's new in Commons Lang 3.0?:

StringUtils.isAlpha, isNumeric and isAlphanumeric now all return false when passed an empty String. Previously they returned true.

Keeping old answer below, for reference and for pre 3.0 users.


Is this logically right?

We have

  1. the behavior of the method
  2. the documentation of the method (which is often viewed as the specification or contract)
  3. the name of the method

In this case 1 and 2 agree with each other; All characters in the empty string are unicode digits. (Or equivalently, no characters in the empty string are not unicode digits.) This what logicians call vacuously true and somewhat counter intuitive. It's like saying that all elephants in my apartment are green. It's true, since there are no elephants in my apartment.

Item 3 however (the name of the method) is naturally interpreted as a method that returns true if the given string represents a number.

So, either it's a documentation and implementation bug, or it's a naming bug. There's no right or wrong answer to that.

A bug was filed here. The maintainers take the stand point that it's intended behavior.

Why do they see empty string as numeric?

While the name of the method may lead you to believe the method should return true only for strings that represents a number, the spec actually says it should return true for if the string contains only unicode digits.

You say,

I'm confused because specification says: "Checks if the String contains only unicode digits." I don't see that "" contains digits....

Note that the empty string does not contain anything else than unicode digits. Therefore the method returns true.

aioobe
  • 413,195
  • 112
  • 811
  • 826
  • 4
    You could just aswell argue that none of the characters in the empty string are unicode digits. – Klaus Byskov Pedersen Oct 20 '10 at 12:41
  • 1
    Yes! Exactly! I don't see any unicode digits in empty string as well! – Andriy Sholokh Oct 20 '10 at 12:44
  • 1
    It occurs to me it's probably for input validation: you can have separate "is numeric" and "is empty" validation checks and by this definition the two are completely orthogonal. – Rup Oct 20 '10 at 12:54
  • 1
    Well... From this point of view: "It is what logicians call "vacuously true". It's like saying that all elephants in my apartment are green. It's true, since there are no elephants in my apartment." - specification is correct. But this is very arguing for me... This is the same if I say: "This is true that Joseph a millioner" and if Joseph does not have money at all... Funny :) – Andriy Sholokh Oct 20 '10 at 13:00
  • 1
    Yes... This is very correct statement "A string contains only unicode digits, if and only if it does not contain non-unicode digits. The empty string clearly does not contain non-unicode digits, therefore it contains only unicode digits."... But could also say "string contains only non-digit characters, if and only if it does not contain digit characters, therefore "" -contains non-digit characters" :) Such a confuse as for me :) – Andriy Sholokh Oct 20 '10 at 13:13
  • 1
    Well, not really. You could however say that the empty string contains only digit-characters, and only non-digit characters. (It contains only characters that represent digits and non-digits. No such characters exists, but still all characters in the empty string satisfy such requirement.) – aioobe Oct 20 '10 at 13:23
  • The behavior as stated by the method name is **not** logically correct; that being said, the javadoc description is logically correct. The method name is "is numeric", but `""` is not numeric; this is a bug. It was indeed admitted as a bug but decided to be left as-is for backwards compatibility. It's dangerous to think that javadoc should trump the method name in terms of which one should be believe; the name is always visible, the javadoc isn't. Just goes to show how important naming is, and how it's been touted as one of the hardest problems in computer science. – Matt Quigley Nov 23 '15 at 21:33
  • We have 1) behavior, 2) documentation, 3) name. In this case 1 and 2 agree with each other, but not with 3. Where's the bug? In 1 and 2, or in 3? There's obviously no right or wrong answer. You can argue that the documentation of the method is the ultimate contract (which is in fact the most common point of view) in which case it's a "method name bug". Or you could argue that they got everything wrong except the name of the method, in which case it's an implementation and documentation bug. – aioobe Nov 24 '15 at 06:23
  • Fixed now. Empty string returns false in the current implementation. – Milo van der Zee Aug 22 '17 at 11:17
7

There was not only me who asked this question :) People were opening this defect in Apache's Jira: https://issues.apache.org/jira/browse/LANG-428

They closed without fixing it only to keep backwards compatibility (to follow method specification).

But everybody agreed that current behavior of method is wrong.

Buhake Sindi
  • 87,898
  • 29
  • 167
  • 228
Andriy Sholokh
  • 852
  • 2
  • 6
  • 15
  • 1
    Quote from the link you gave: "An empty String has no characters, so cannot contain an illegal character."....hence why it's an acceptable behaviour. – Buhake Sindi Oct 20 '10 at 16:33
  • 1
    But it also does not contain legal character. One guy asked a reasonable question in comments: "Maybe the method could be better named isNotNonNumeric()?" I 100% agree with him. My point is... If to write "17"+"256" - everything is clear... but ""+"256"... well... Empty string should not be considered as some digit, either 0 or 1 or something else. – Andriy Sholokh Oct 20 '10 at 17:12
  • I agree. The name of the function is slightly misleading and unfortunate. It could for instance have been called `containsOnlyDigits` or `isNotNonNumeric` as you suggest. There are a few surprises like this regarding the empty string. For example, would you say that an empty string ever contains anything? That is, should `"".contains(.....)` ever evaluate to true? Well it does! (I'll leave it as an exercise for you to figure out how ;) You'll just have to get used to these, shall we say "counter-intuitive properties" of the empty string. – aioobe Oct 20 '10 at 18:44
  • They could at least deprecate it and replace it with `isActuallyNumeric()` or something. – Hakanai Mar 13 '12 at 01:08
6

java.lang.Integer.parseInt("") will fail.

It's not a matter of logic. It's not a matter of common sense either - there wasn't any number that's represented by no symbol. There's no strong argument why an empty string should represent 0.

If the method name is containsOnlyNumeric(), it is natural to return true for "" according to our math textbooks. However, the method name is isNumeric(), the treatment of "" isn't natural. Also, there's no apparent reason why null should return false. I would throw exception for null.

But it is what it is, it is well documented and what more can you ask for?

irreputable
  • 44,725
  • 9
  • 65
  • 93
4

first check the condition the string is empty() or not.

if(StringUtils.isNotEmpty(str) && StringUtils.isNumeric(str)) {

}

then your problem will be solved.

but still one more problem is you pass negative values like

str = "-1";

StringUtils.isNumeric(str) it will be false.

You need to take care for this condition.

Ranga Reddy
  • 2,936
  • 4
  • 29
  • 41
  • 2
    Maybe you want to use [`isNotEmpty`](https://commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/apache/commons/lang/StringUtils.html#isNotEmpty%28java.lang.String%29) in your first snippet? – aioobe Feb 15 '16 at 15:22
0

There is another solution. NumberUtils.isNumber This checks if it is a number either Long, Double, Integer.

Hope this help

Community
  • 1
  • 1
Najor
  • 639
  • 5
  • 11
0

As of Commons Lang 3.5, NumberUtils.isCreatable is the way to do this. See this answer for a more detailed description.

squaregoldfish
  • 709
  • 8
  • 20