Java中检查字符串是否为数字的6种性能比较

本教程介绍6种方法来检测给定的String是否为 数字,并最后比较它们的性能方法?

1、使用核心纯Java
最简单、最可靠的方法是使用 Java 的内置方法解析它(但是性能不一定最好):

  1. Integer.parseInt(String)
  2. Float.parseFloat(String)
  3. Double.parseDouble(String)
  4. Long.parseLong(String)
  5. new BigInteger(String)


  try {
        long dL = Long.parseLong(strNum);
    } catch (NumberFormatException nfe) {
        return false;
    }
    return true;

2、使用正则表达式
使用正则表达式-?\d+(\.\d+)? 匹配由正整数或负整数和浮点数组成的数字字符串。

String testS = "33333eee";
System.out.println(testS.matches(
"\\d+")?"ok":"no");


3、使用 Apache Commons的NumberUtils.isCreatable
引入依赖:

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.13.0</version>
</dependency>

Apache Commons 的NumberUtils提供了一个静态方法NumberUtils.isCreatable(String),它检查String是否是有效的 Java 数字。
该方法接受:

  1. 以 0x 或 0X 开头的十六进制数
  2. 以 0 开头的八进制数
  3. 科学计数法(例如 1.05e-10)
  4. 用类型限定符标记的数字(例如 1L 或 2.2d)

assertThat(NumberUtils.isCreatable("22")).isTrue();
assertThat(NumberUtils.isCreatable(
"5.05")).isTrue();
assertThat(NumberUtils.isCreatable(
"-200")).isTrue();
assertThat(NumberUtils.isCreatable(
"10.0d")).isTrue();
assertThat(NumberUtils.isCreatable(
"1000L")).isTrue();
assertThat(NumberUtils.isCreatable(
"0xFF")).isTrue();
assertThat(NumberUtils.isCreatable(
"07")).isTrue();
assertThat(NumberUtils.isCreatable(
"2.99e+8")).isTrue();
 
assertThat(NumberUtils.isCreatable(null)).isFalse();
assertThat(NumberUtils.isCreatable(
"")).isFalse();
assertThat(NumberUtils.isCreatable(
"abc")).isFalse();
assertThat(NumberUtils.isCreatable(
" 22 ")).isFalse();
assertThat(NumberUtils.isCreatable(
"09")).isFalse();

请注意,我们分别在第 6、7 和 8 行中获得了十六进制数、八进制数和科学计数法的真实断言。
另外,在第 14 行,字符串“09”返回false,因为前面的“0”表示这是一个八进制数,而“09”不是有效的八进制数。

4、 使用 Apache Commons的NumberUtils.isParsable(String) 
NumberUtils.isParsable (String)方法检查给定的String是否可解析。
可解析的数字是那些可以通过任何解析方法成功解析的数字,例如Integer.parseInt(String)、Long.parseLong(String)、Float.parseFloat(String)或Double.parseDouble(String)。
与NumberUtils.isCreatable()不同,此方法不接受十六进制数字、科学记数法或以任何类型的限定符(如'f'、'F'、'd' 、'D' 、'l'或'L结尾的字符串) '。

assertThat(NumberUtils.isParsable("22")).isTrue();
assertThat(NumberUtils.isParsable(
"-23")).isTrue();
assertThat(NumberUtils.isParsable(
"2.2")).isTrue();
assertThat(NumberUtils.isParsable(
"09")).isTrue();

assertThat(NumberUtils.isParsable(null)).isFalse();
assertThat(NumberUtils.isParsable(
"")).isFalse();
assertThat(NumberUtils.isParsable(
"6.2f")).isFalse();
assertThat(NumberUtils.isParsable(
"9.8d")).isFalse();
assertThat(NumberUtils.isParsable(
"22L")).isFalse();
assertThat(NumberUtils.isParsable(
"0xFF")).isFalse();
assertThat(NumberUtils.isParsable(
"2.99e+8")).isFalse();

在第 4 行,与NumberUtils.isCreatable()不同,以字符串“0”开头的数字不被视为八进制数,而是普通的十进制数,因此它返回 true。

5、 使用 Apache Commons的StringUtils.isNumeric(CharSequence )  
方法StringUtils.isNumeric(CharSequence)严格检查 Unicode 数字。这意味着:

  1. 任何语言中任何 Unicode 数字的数字都是可接受的
  2. 由于小数点不被视为 Unicode 数字,因此它无效
  3. 前缀符号(无论是正的还是负)也是不可接受的

assertThat(StringUtils.isNumeric("123")).isTrue();
assertThat(StringUtils.isNumeric(
"١٢٣")).isTrue();
assertThat(StringUtils.isNumeric(
"१२३")).isTrue();
 
assertThat(StringUtils.isNumeric(null)).isFalse();
assertThat(StringUtils.isNumeric(
"")).isFalse();
assertThat(StringUtils.isNumeric(
"  ")).isFalse();
assertThat(StringUtils.isNumeric(
"12 3")).isFalse();
assertThat(StringUtils.isNumeric(
"ab2c")).isFalse();
assertThat(StringUtils.isNumeric(
"12.3")).isFalse();
assertThat(StringUtils.isNumeric(
"-123")).isFalse();

请注意,第 2 行和第 3 行的输入参数分别代表阿拉伯数字 123 和梵文数字 123。由于它们是有效的 Unicode 数字,因此本方法返回 true。

5、 使用 Apache Commons的StringUtils.isNumericSpace(CharSequence)
StringUtils.isNumericSpace  (CharSequence)严格检查 Unicode 数字和/或空格。这与StringUtils.isNumeric()相同,只是它也接受空格,不仅是前导空格和尾随空格,而且还接受它们位于数字之间的空格:

assertThat(StringUtils.isNumericSpace("123")).isTrue();
assertThat(StringUtils.isNumericSpace(
"١٢٣")).isTrue();
assertThat(StringUtils.isNumericSpace(
"")).isTrue();
assertThat(StringUtils.isNumericSpace(
"  ")).isTrue();
assertThat(StringUtils.isNumericSpace(
"12 3")).isTrue();
 
assertThat(StringUtils.isNumericSpace(null)).isFalse();
assertThat(StringUtils.isNumericSpace(
"ab2c")).isFalse();
assertThat(StringUtils.isNumericSpace(
"12.3")).isFalse();
assertThat(StringUtils.isNumericSpace(
"-123")).isFalse();

基准测试
我们使用Integer.MAX_VALUE。然后将针对我们所有的实现来测试该值:

Benchmark                                     Mode  Cnt    Score   Error  Units
Benchmarking.1、usingCoreJava                    avgt   20   57.241 ± 0.792  ns/op
Benchmarking.2、usingRegularExpressions         avgt  20 101.580 ± 4.244 ns/op
Benchmarking.3、usingNumberUtils_isCreatable     avgt   20   26.711 ± 1.110  ns/op
Benchmarking.4、usingNumberUtils_isParsable      avgt   20   46.577 ± 1.973  ns/op
Benchmarking.5、usingStringUtils_isNumeric       avgt   20   35.885 ± 1.691  ns/op
Benchmarking.6、usingStringUtils_isNumericSpace  avgt   20   31.979 ± 1.393  ns/op

成本最高的操作是正则表达式。之后是我们基于 Java 的核心解决方案。

使用一组更多样化的测试来获得更具代表性的基准:

  • 95 个值是数字(0-94 和Integer.MAX_VALUE)
  •  包含数字,但格式仍然错误 — ' x0 '、' 0..005 ' 和 ' –11 '
  •  仅包含文本
  •  为空

Benchmark                                     Mode  Cnt      Score     Error  Units
Benchmarking.usingCoreJava                    avgt   20  10162.872 ± 798.387  ns/op
Benchmarking.usingRegularExpressions          avgt   20   7168.761 ± 344.597  ns/op
Benchmarking.usingNumberUtils_isCreatable     avgt   20   1703.243 ± 108.244  ns/op
Benchmarking.usingNumberUtils_isParsable      avgt   20   1589.915 ± 203.052  ns/op
Benchmarking.usingStringUtils_isNumeric       avgt   20   1071.753 ±   8.657  ns/op
Benchmarking.usingStringUtils_isNumericSpace  avgt   20   1157.722 ±  24.139  ns/op


从这一结果中,我们可以了解到,NumberFormatException 的抛出和处理(仅在 5% 的情况下发生)对整体性能的影响相对较大。

此外,我们还可以有把握地得出结论:为了获得最佳性能,我们应该使用 Commons 库中的方法或类似方法。