从性能上来看,parseInt
等解决方案要比其他解决方案差得多,因为它们至少需要异常处理。
我运行了jmh测试,并发现使用charAt
迭代字符串并将字符与边界字符进行比较是测试字符串是否仅包含数字的最快方法。
JMH测试
这些测试比较了Character.isDigit
与Pattern.matcher().matches
与Long.parseLong
与检查字符值的性能。
这些方法对于非ASCII字符串和包含+/-符号的字符串可能会产生不同的结果。
测试以吞吐量模式(越大越好)运行,带有5个预热迭代和5个测试迭代。
结果
请注意,对于第一个测试负载,parseLong
几乎比isDigit
慢了100倍。
Benchmark Mode Cnt Score Error Units
testIsDigit thrpt 5 9.275 ± 2.348 ops/s
testPattern thrpt 5 2.135 ± 0.697 ops/s
testParseLong thrpt 5 0.166 ± 0.021 ops/s
Benchmark Mode Cnt Score Error Units
testCharBetween thrpt 5 16.773 ± 0.401 ops/s
testCharAtIsDigit thrpt 5 8.917 ± 0.767 ops/s
testCharArrayIsDigit thrpt 5 6.553 ± 0.425 ops/s
testPattern thrpt 5 1.287 ± 0.057 ops/s
testIntStreamCodes thrpt 5 0.966 ± 0.051 ops/s
testParseLong thrpt 5 0.174 ± 0.013 ops/s
testParseInt thrpt 5 0.078 ± 0.001 ops/s
测试套件
@State(Scope.Benchmark)
public class StringIsNumberBenchmark {
private static final long CYCLES = 1_000_000L;
private static final String[] STRINGS = {"12345678901","98765432177","58745896328","35741596328", "123456789a1", "1a345678901", "1234567890 "};
private static final Pattern PATTERN = Pattern.compile("\\d+");
@Benchmark
public void testPattern() {
for (int i = 0; i < CYCLES; i++) {
for (String s : STRINGS) {
boolean b = false;
b = PATTERN.matcher(s).matches();
}
}
}
@Benchmark
public void testParseLong() {
for (int i = 0; i < CYCLES; i++) {
for (String s : STRINGS) {
boolean b = false;
try {
Long.parseLong(s);
b = true;
} catch (NumberFormatException e) {
}
}
}
}
@Benchmark
public void testCharArrayIsDigit() {
for (int i = 0; i < CYCLES; i++) {
for (String s : STRINGS) {
boolean b = false;
for (char c : s.toCharArray()) {
b = Character.isDigit(c);
if (!b) {
break;
}
}
}
}
}
@Benchmark
public void testCharAtIsDigit() {
for (int i = 0; i < CYCLES; i++) {
for (String s : STRINGS) {
boolean b = false;
for (int j = 0; j < s.length(); j++) {
b = Character.isDigit(s.charAt(j));
if (!b) {
break;
}
}
}
}
}
@Benchmark
public void testIntStreamCodes() {
for (int i = 0; i < CYCLES; i++) {
for (String s : STRINGS) {
boolean b = false;
b = s.chars().allMatch(c -> c > 47 && c < 58);
}
}
}
@Benchmark
public void testCharBetween() {
for (int i = 0; i < CYCLES; i++) {
for (String s : STRINGS) {
boolean b = false;
for (int j = 0; j < s.length(); j++) {
char charr = s.charAt(j);
b = '0' <= charr && charr <= '9';
if (!b) {
break;
}
}
}
}
}
}
2018年2月23日更新
- 添加了两个更多的测试案例 - 一个使用
charAt
而不是创建额外的数组,另一个使用 char 代码的 IntStream
- 在循环测试案例中,如果发现非数字,则立即退出循环
- 对于循环测试案例中的空字符串,返回 false
2018年2月23日更新
- 添加了一个更多的测试案例(最快的!),它比较 char 值而不使用流
contains
不接受正则表达式作为输入。请使用matches("\\d{2,}")
,或尝试使用Pattern
和Matcher
。 - Guillaume PoletPattern.matches("[a-zA-Z]+", text) == false
可以简化为!Pattern.matches("[a-zA-Z]+", text)
。 - SARoseboolean isNumeric = someString.chars().allMatch(x -> Character.isDigit(x));
,来源于Max Malysh
的帖子。该代码可用于判断一个字符串是否为数字。 - Yash! oddStr.matches("\\D+")
- MarkHu