本教程介绍6种方法来检测给定的String是否为 数字,并最后比较它们的性能方法?
1、使用核心纯Java
最简单、最可靠的方法是使用 Java 的内置方法解析它(但是性能不一定最好):
- Integer.parseInt(String)
- Float.parseFloat(String)
- Double.parseDouble(String)
- Long.parseLong(String)
- 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 数字。
该方法接受:
- 以 0x 或 0X 开头的十六进制数
- 以 0 开头的八进制数
- 科学计数法(例如 1.05e-10)
- 用类型限定符标记的数字(例如 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 数字。这意味着:
- 任何语言中任何 Unicode 数字的数字都是可接受的
- 由于小数点不被视为 Unicode 数字,因此它无效
- 前缀符号(无论是正的还是负)也是不可接受的
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 库中的方法或类似方法。