Hiệu suất khôn ngoan parseInt
và như vậy là tồi tệ hơn nhiều so với các giải pháp khác, bởi vì ít nhất yêu cầu xử lý ngoại lệ.
Tôi đã chạy thử nghiệm jmh và nhận thấy rằng việc lặp qua Chuỗi bằng cách sử dụng charAt
và so sánh ký tự với ký tự biên là cách nhanh nhất để kiểm tra nếu chuỗi chỉ chứa các chữ số.
Thử nghiệm JMH
Các thử nghiệm so sánh hiệu suất của Character.isDigit
vs Pattern.matcher().matches
vs Long.parseLong
vs kiểm tra giá trị char.
Những cách này có thể tạo ra kết quả khác nhau cho các chuỗi không phải chuỗi ascii và chuỗi chứa dấu +/-.
Các thử nghiệm chạy ở chế độ Thông lượng ( lớn hơn là tốt hơn ) với 5 lần lặp khởi động và 5 lần lặp thử nghiệm.
Các kết quả
Lưu ý rằng parseLong
chậm hơn gần 100 lần so isDigit
với tải thử nghiệm đầu tiên.
## Test load with 25% valid strings (75% strings contain non-digit symbols)
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
## Test load with 50% valid strings (50% strings contain non-digit symbols)
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
Bộ kiểm tra
@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) {
// no-op
}
}
}
}
@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;
}
}
}
}
}
}
Cập nhật vào ngày 23 tháng 2 năm 2018
- Thêm hai trường hợp nữa - một trường hợp sử dụng
charAt
thay vì tạo mảng bổ sung và trường hợp khác sử dụng IntStream
mã char
- Thêm ngắt ngay lập tức nếu không tìm thấy chữ số cho các trường hợp kiểm tra lặp
- Trả về false cho chuỗi rỗng cho các trường hợp kiểm tra lặp
Cập nhật vào ngày 23 tháng 2 năm 2018
- Thêm một trường hợp thử nghiệm (nhanh nhất!) So sánh giá trị char mà không cần sử dụng luồng
matches("\\d{2,}")
hoặc thử với mộtPattern
vàMatcher