Przetestowałem obiecujące podejścia przy użyciu JMH . Pełny kod testu porównawczego .
Założenie podczas testów (aby uniknąć sprawdzania przypadków narożnych za każdym razem): wejściowa długość ciągu jest zawsze większa niż 1.
Wyniki
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
Wynik to liczba operacji na sekundę, im więcej, tym lepiej.
Testy
test1
było pierwszym podejściem Andy'ego i Hllinka:
string = Character.toLowerCase(string.charAt(0)) + string.substring(1);
test2
było drugim podejściem Andy'ego. Introspector.decapitalize()
Sugeruje to również Daniel, ale bez dwóch if
stwierdzeń. Pierwszy if
został usunięty z powodu założenia testowego. Drugi został usunięty, ponieważ naruszał poprawność (tzn. Wejście "HI"
zwracało "HI"
). To był prawie najszybszy.
char c[] = string.toCharArray();
c[0] = Character.toLowerCase(c[0]);
string = new String(c);
test3
była modyfikacją test2
, ale zamiast tego Character.toLowerCase()
dodałem 32, które działa poprawnie wtedy i tylko wtedy, gdy łańcuch jest w ASCII. To było najszybsze. c[0] |= ' '
z komentarza Mike'a dał taki sam występ.
char c[] = string.toCharArray();
c[0] += 32;
string = new String(c);
test4
używany StringBuilder
.
StringBuilder sb = new StringBuilder(string);
sb.setCharAt(0, Character.toLowerCase(sb.charAt(0)));
string = sb.toString();
test5
użył dwóch substring()
połączeń.
string = string.substring(0, 1).toLowerCase() + string.substring(1);
test6
używa odbicia, aby zmienić char value[]
bezpośrednio w ciągu. To było najwolniejsze.
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();
}
Wnioski
Jeśli długość ciągu jest zawsze większa niż 0, użyj test2
.
Jeśli nie, musimy sprawdzić narożniki:
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);
}
Jeśli jesteś pewien, że twój tekst będzie zawsze w ASCII i szukasz ekstremalnej wydajności, ponieważ znalazłeś ten kod w wąskim gardle, użyj test3
.