Performans açısından parseInt
ve benzeri diğer çözümlerden çok daha kötüdür, çünkü en azından istisna yönetimi gerektirir.
Ben jmh testleri çalıştırmak ve kullanarak String üzerinden yineleme bulduk charAt
dizi ve sınır karakterleri ile chars karşılaştırma karşılaştırarak sadece dizi içeriyorsa test etmek için en hızlı yoludur.
JMH testi
Testler Character.isDigit
vs Pattern.matcher().matches
vs performans karşılaştırmakLong.parseLong
char karakterlerini .
Bu yollar, ascii olmayan dizeler ve +/- işaretleri içeren dizeler için farklı sonuçlar üretebilir.
Testler Verim modunda çalışır ( daha büyük daha iyidir , 5 ısınma yineleme ve 5 test yineleme ile ) çalışır.
Sonuçlar
İlk test yükünden parseLong
neredeyse 100 kat daha yavaş olduğunu unutmayın isDigit
.
## 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
Test odası
@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;
}
}
}
}
}
}
23 Şub 2018 tarihinde güncellendi
- İki örnek daha ekleyin - biri
charAt
ekstra dizi oluşturmak yerine diğeri IntStream
karakter kodlarını kullanmak için
- Döngülü test senaryoları için rakamsız bulunursa anında mola ekleyin
- Döngülü test senaryoları için boş dize için false döndür
23 Şub 2018 tarihinde güncellendi
- Akış değerini kullanmadan karakter değerini karşılaştıran bir test örneği (en hızlı!) Ekleyin
matches("\\d{2,}")
da birPattern
ve ile deneyinMatcher