最有效的方法是使String小写的第一个字符?

时间:2010-10-29 14:36:38

标签: java string performance optimization

制作String小写字母的第一个字符的最有效方法是什么?

我可以想到很多方法:

charAt()substring()

一起使用
String input   = "SomeInputString";
String output  = Character.toLowerCase(input.charAt(0)) +
                   (input.length() > 1 ? input.substring(1) : "");

或使用char数组

 String input  = "SomeInputString";
 char c[]      = input.toCharArray();
 c[0]          = Character.toLowerCase(c[0]);
 String output = new String(c);

我相信还有很多其他很好的方法可以实现这一目标。你推荐什么?

11 个答案:

答案 0 :(得分:106)

我使用JMH测试了有希望的方法。完整基准code

测试期间的假设(避免每次都检查角落情况):输入字符串长度始终大于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

得分是每秒的操作次数越多越好。

测试

  1. test1首先是安迪和Hllink的方法:

    string = Character.toLowerCase(string.charAt(0)) + string.substring(1);
    
  2. test2是安迪的第二个方法。 Daniel也建议Introspector.decapitalize(),但没有两个if语句。由于测试假设,首先删除了if。第二个被删除,因为它违反了正确性(即输入"HI"将返回"HI")。这几乎是最快的。

    char c[] = string.toCharArray();
    c[0] = Character.toLowerCase(c[0]);
    string = new String(c);
    
  3. test3test2的修改,但是我添加了32,而不是Character.toLowerCase(),当且仅当字符串是ASCII时,才能正常工作。这是最快的。来自Mike的commentc[0] |= ' '给出了同样的表现。

    char c[] = string.toCharArray();
    c[0] += 32;
    string = new String(c);
    
  4. test4使用StringBuilder

    StringBuilder sb = new StringBuilder(string);
    sb.setCharAt(0, Character.toLowerCase(sb.charAt(0)));
    string = sb.toString();
    
  5. test5使用了两次substring()次来电。

    string = string.substring(0, 1).toLowerCase() + string.substring(1);
    
  6. test6使用反射直接在String中更改char value[]。这是最慢的。

    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();
    }
    
  7. 结论

    如果字符串长度始终大于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

答案 1 :(得分:88)

如果您不想使用第三方库,我会遇到一个不错的选择:

import java.beans.Introspector;

Assert.assertEquals("someInputString", Introspector.decapitalize("SomeInputString"));

答案 2 :(得分:20)

当谈到字符串操作时,请查看Jakarta Commons Lang StringUtils

答案 3 :(得分:14)

如果您想使用Apache Commons,您可以执行以下操作:

import org.apache.commons.lang3.text.WordUtils;
[...] 
String s = "SomeString"; 
String firstLower = WordUtils.uncapitalize(s);

结果:someString

答案 4 :(得分:10)

尽管采用了面向字符的方法,我建议使用面向字符串的解决方案。 String.toLowerCase是特定于区域设置的,因此我会考虑此问题。根据{{​​3}},String.toLowerCase更喜欢小写。 此外,面向字符的解决方案不是完全兼容unicode,因为Character.toLowerCase无法处理补充字符。

public static final String uncapitalize(final String originalStr,
            final Locale locale) {
        final int splitIndex = 1;
        final String result;
        if (originalStr.isEmpty()) {
        result = originalStr;
        } else {
        final String first = originalStr.substring(0, splitIndex).toLowerCase(
                locale);
        final String rest = originalStr.substring(splitIndex);
        final StringBuilder uncapStr = new StringBuilder(first).append(rest);
        result = uncapStr.toString();
        }
        return result;
    }

<强>更新 作为一个例子,区域设置的重要性让我们在土耳其语和德语中使用小写I

System.out.println(uncapitalize("I", new Locale("TR","tr")));
System.out.println(uncapitalize("I", new Locale("DE","de")));

将输出两个不同的结果:

  

I

     

答案 5 :(得分:7)

Java中的字符串是不可变的,因此无论哪种方式都会创建一个新的字符串。

您的第一个示例可能会稍微提高效率,因为它只需要创建一个新字符串而不是临时字符数组。

答案 6 :(得分:3)

一种非常简短的静态方法,用于存档您想要的内容:

public static String decapitalizeString(String string) {
    return string == null || string.isEmpty() ? "" : Character.toLowerCase(string.charAt(0)) + string.substring(1);
}

答案 7 :(得分:2)

如果你需要的是非常简单的(例如java类名,没有语言环境),你也可以使用CaseFormat库中的Google Guava类。

String converted = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_CAMEL, "FooBar");
assertEquals("fooBar", converted);

或者您可以准备和重用转换器对象,这可能更有效。

Converter<String, String> converter=
    CaseFormat.UPPER_CAMEL.converterTo(CaseFormat.LOWER_CAMEL);

assertEquals("fooBar", converter.convert("FooBar"));

为了更好地理解Google Guava字符串操作的哲学,请查看this wiki page

答案 8 :(得分:1)

String testString = "SomeInputString";
String firstLetter = testString.substring(0,1).toLowerCase();
String restLetters = testString.substring(1);
String resultString = firstLetter + restLetters;

答案 9 :(得分:1)

我今天才到这里来。试图以最行人的方式自己做。这花了一条线,很长。

String str = "TaxoRank"; 

System.out.println(" Before str = " + str); 

str = str.replaceFirst(str.substring(0,1), str.substring(0,1).toLowerCase());

System.out.println(" After str = " + str);

给出:

在str = TaxoRanks之前

在str = taxoRanks之后

答案 10 :(得分:1)

val str = "Hello"
s"${str.head.toLower}${str.tail}"

结果:

res4: String = hello