Я протестировал перспективные подходы с помощью 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
.