Я перевірив перспективні підходи, використовуючи JMH . Повний контрольний код .
Припущення під час тестів (щоб уникнути перевірки кутових випадків кожного разу): вхідна довжина рядка завжди більше 1.
Результати
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
Оцінка - це кількість операцій в секунду, чим більше, тим краще.
Тести
test1
був першим підходом Енді та Хлінка:
string = Character.toLowerCase(string.charAt(0)) + string.substring(1);
test2
був другим підходом Енді. Це також Introspector.decapitalize()
пропонується Даніелем, але без двох if
тверджень. Перший if
був вилучений через припущення про тестування. Другий видалено, оскільки він порушує правильність (тобто введення "HI"
повернеться "HI"
). Це було майже найшвидше.
char c[] = string.toCharArray();
c[0] = Character.toLowerCase(c[0]);
string = new String(c);
test3
була модифікацією test2
, але замість цього Character.toLowerCase()
я додав 32, яка працює правильно тоді і тільки тоді, коли рядок знаходиться в ASCII. Це було найшвидше. c[0] |= ' '
з коментаря Майка дав такий самий виступ.
char c[] = string.toCharArray();
c[0] += 32;
string = new String(c);
test4
б / в StringBuilder
.
StringBuilder sb = new StringBuilder(string);
sb.setCharAt(0, Character.toLowerCase(sb.charAt(0)));
string = sb.toString();
test5
використав два substring()
дзвінки.
string = string.substring(0, 1).toLowerCase() + string.substring(1);
test6
використовує відображення для зміни char value[]
безпосередньо в String. Це було найповільніше.
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();
}
Висновки
Якщо довжина рядка завжди перевищує 0, використовуйте test2
.
Якщо ні, ми повинні перевірити кутові корпуси:
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);
}
Якщо ви впевнені, що ваш текст завжди буде в ASCII, і ви шукаєте надзвичайної продуктивності, оскільки ви знайшли цей код у вузькому місці, використовуйте test3
.