Performances parseInt
et autres sont bien pires que les autres solutions, car elles exigent au moins la gestion des exceptions.
J'ai effectué des tests jmh et j'ai constaté que l'itération sur String en utilisant charAt
et la comparaison des caractères avec les caractères de délimitation est le moyen le plus rapide de tester si une chaîne ne contient que des chiffres.
Essais de JMH
Les tests comparent les performances de Character.isDigit
vs Pattern.matcher().matches
vs Long.parseLong
par rapport à la vérification des valeurs des caractères.
Ces méthodes peuvent produire des résultats différents pour les chaînes de caractères non ascii et les chaînes de caractères contenant des signes +/-.
Tests exécutés en mode débit ( Plus c'est grand, mieux c'est ) avec 5 itérations de réchauffement et 5 itérations de test.
Résultats
Notez que parseLong
est presque 100 fois plus lent que isDigit
pour la première charge d'essai.
## 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
Suite de tests
@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;
}
}
}
}
}
}
Mis à jour le 23 février 2018
- Ajoutez deux autres cas - l'un utilisant
charAt
au lieu de créer un tableau supplémentaire et un autre en utilisant IntStream
de codes de caractères
- Ajout d'une interruption immédiate en cas de non-digit trouvé pour les cas de test en boucle
- Renvoyer false pour une chaîne vide pour les cas de test bouclés
Mis à jour le 23 février 2018
- Ajoutez un scénario de test supplémentaire (le plus rapide !) qui compare la valeur d'un caractère sans utiliser le flux.
5 votes
Contains ne prend pas une regexp en entrée. Utilisez soit
matches("\\d{2,}")
ou essayez avec unPattern
yMatcher
0 votes
La chaîne peut-elle avoir une valeur décimale ou seulement des valeurs entières ?
5 votes
Pourquoi vérifiez-vous que text.length() > 2 ? Quelle en est la raison ?
1 votes
@RedHatcc
Pattern.matches("[a-zA-Z]+", text) == false
peut être simplifié en!Pattern.matches("[a-zA-Z]+", text)
7 votes
Utilisation de l'API de streaming java
boolean isNumeric = someString.chars().allMatch(x -> Character.isDigit(x));
formulaireMax Malysh
Poste.0 votes
Cette regex négative me semble la plus simple :
! oddStr.matches("\\D+")