Probé los enfoques prometedores utilizando JMH . Código de referencia completo .
Supuesto durante las pruebas (para evitar comprobar los casos de las esquinas cada vez): la longitud de la cadena de entrada es siempre mayor que 1.
Resultados
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
La puntuación son operaciones por segundo, cuanto más, mejor.
Pruebas
test1
fue el primer enfoque de Andy e Hllink:
string = Character.toLowerCase(string.charAt(0)) + string.substring(1);
test2
fue el segundo acercamiento de Andy. También lo Introspector.decapitalize()
sugiere Daniel, pero sin dos if
declaraciones. Primero if
se eliminó debido al supuesto de prueba. El segundo fue eliminado porque violaba la corrección (es decir, la entrada "HI"
volvería "HI"
). Este fue casi el más rápido.
char c[] = string.toCharArray();
c[0] = Character.toLowerCase(c[0]);
string = new String(c);
test3
era una modificación de test2
, pero en lugar de Character.toLowerCase()
, estaba agregando 32, que funciona correctamente si y solo si la cadena está en ASCII. Este fue el más rápido. c[0] |= ' '
del comentario de Mike dio la misma actuación.
char c[] = string.toCharArray();
c[0] += 32;
string = new String(c);
test4
utilizado StringBuilder
.
StringBuilder sb = new StringBuilder(string);
sb.setCharAt(0, Character.toLowerCase(sb.charAt(0)));
string = sb.toString();
test5
utilizó dos substring()
llamadas.
string = string.substring(0, 1).toLowerCase() + string.substring(1);
test6
usa la reflexión para cambiar char value[]
directamente en String. Este fue el más lento.
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();
}
Conclusiones
Si la longitud de la cadena es siempre mayor que 0, utilice test2
.
Si no es así, tenemos que comprobar los casos de las esquinas:
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 está seguro de que su texto siempre estará en ASCII y está buscando un rendimiento extremo porque encontró este código en el cuello de botella, use test3
.