In parseInt
Bezug auf die Leistung und dergleichen sind sie viel schlechter als andere Lösungen, da zumindest eine Ausnahmebehandlung erforderlich ist.
Ich habe jmh-Tests ausgeführt und festgestellt, dass das Überlaufen von String using charAt
und das Vergleichen von Zeichen mit Grenzzeichen der schnellste Weg ist, um zu testen, ob der String nur Ziffern enthält.
JMH-Tests
Tests vergleichen die Leistung von Character.isDigit
vs Pattern.matcher().matches
vs.Long.parseLong
vs überprüfen Zeichenwerte.
Diese Methoden können zu unterschiedlichen Ergebnissen für Nicht-ASCII-Zeichenfolgen und Zeichenfolgen mit +/- Zeichen führen.
Tests werden im Durchsatzmodus ausgeführt ( größer ist besser ) mit 5 Aufwärmiterationen und 5 Testiterationen ausgeführt.
Ergebnisse
Beachten Sie, dass dies parseLong
fast 100-mal langsamer ist als isDigit
bei der ersten Testlast.
## 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
Testsuite
@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;
}
}
}
}
}
}
Aktualisiert am 23. Februar 2018
- Fügen Sie zwei weitere Fälle hinzu - einen mithilfe
charAt
eines zusätzlichen Arrays und einen mithilfe IntStream
von Zeichencodes
- Fügen Sie eine sofortige Unterbrechung hinzu, wenn für Testfälle mit Schleifen keine Ziffer gefunden wurde
- Geben Sie false für eine leere Zeichenfolge für Testfälle mit Schleifen zurück
Aktualisiert am 23. Februar 2018
- Fügen Sie einen weiteren Testfall hinzu (den schnellsten!), Der den Zeichenwert ohne Verwendung von Stream vergleicht
matches("\\d{2,}")
oder versuchen Sie es mit einemPattern
undMatcher