J'ai testé les approches prometteuses en utilisant JMH . Code de référence complet .
Hypothèse lors des tests (pour éviter de vérifier les cas d'angle à chaque fois): la longueur de la chaîne d'entrée est toujours supérieure à 1.
Résultats
Benchmark Mode Cnt Score Error Units
MyBenchmark.test1 thrpt 20 10463220.493 ± 288805.068 ops/s
MyBenchmark.test2 thrpt 20 14730158.709 ± 530444.444 ops/s
MyBenchmark.test3 thrpt 20 16079551.751 ± 56884.357 ops/s
MyBenchmark.test4 thrpt 20 9762578.446 ± 584316.582 ops/s
MyBenchmark.test5 thrpt 20 6093216.066 ± 180062.872 ops/s
MyBenchmark.test6 thrpt 20 2104102.578 ± 18705.805 ops/s
Les scores sont des opérations par seconde, plus il y en a, mieux c'est.
Des tests
test1
était d'abord l'approche d'Andy et Hllink:
string = Character.toLowerCase(string.charAt(0)) + string.substring(1);
test2
était la deuxième approche d'Andy. Il est également Introspector.decapitalize()
suggéré par Daniel, mais sans deux if
déclarations. First a if
été supprimé en raison de l'hypothèse de test. Le second a été supprimé, car il enfreignait l'exactitude (c'est-à-dire que l'entrée "HI"
reviendrait "HI"
). C'était presque le plus rapide.
char c[] = string.toCharArray();
c[0] = Character.toLowerCase(c[0]);
string = new String(c);
test3
était une modification de test2
, mais au lieu de Character.toLowerCase()
, j'ajoutais 32, qui fonctionne correctement si et seulement si la chaîne est en ASCII. C'était le plus rapide. c[0] |= ' '
du commentaire de Mike a donné la même performance.
char c[] = string.toCharArray();
c[0] += 32;
string = new String(c);
test4
utilisé StringBuilder
.
StringBuilder sb = new StringBuilder(string);
sb.setCharAt(0, Character.toLowerCase(sb.charAt(0)));
string = sb.toString();
test5
utilisé deux substring()
appels.
string = string.substring(0, 1).toLowerCase() + string.substring(1);
test6
utilise la réflexion pour changer char value[]
directement dans String. C'était le plus lent.
try {
Field field = String.class.getDeclaredField("value");
field.setAccessible(true);
char[] value = (char[]) field.get(string);
value[0] = Character.toLowerCase(value[0]);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
Conclusions
Si la longueur de la chaîne est toujours supérieure à 0, utilisez test2
.
Sinon, nous devons vérifier les cas d'angle:
public static String decapitalize(String string) {
if (string == null || string.length() == 0) {
return string;
}
char c[] = string.toCharArray();
c[0] = Character.toLowerCase(c[0]);
return new String(c);
}
Si vous êtes sûr que votre texte sera toujours en ASCII et que vous recherchez des performances extrêmes car vous avez trouvé ce code dans le goulot d'étranglement, utilisez test3
.