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

And*_*ndy 92 java string optimization performance

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

我可以想到许多方法来做到这一点:

使用charAt()substring()

String input   = "SomeInputString";
String output  = Character.toLowerCase(input.charAt(0)) +
                   (input.length() > 1 ? input.substring(1) : "");
Run Code Online (Sandbox Code Playgroud)

或者使用char数组

 String input  = "SomeInputString";
 char c[]      = input.toCharArray();
 c[0]          = Character.toLowerCase(c[0]);
 String output = new String(c);
Run Code Online (Sandbox Code Playgroud)

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

Ada*_*zyk 113

我使用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
Run Code Online (Sandbox Code Playgroud)

得分是每秒操作,越多越好.

测试

  1. test1 是第一个Andy和Hllink的方法:

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

    char c[] = string.toCharArray();
    c[0] = Character.toLowerCase(c[0]);
    string = new String(c);
    
    Run Code Online (Sandbox Code Playgroud)
  3. test3是一个修改test2,但Character.toLowerCase()我没有添加32,当且仅当字符串是ASCII时才能正常工作.这是最快的.c[0] |= ' '来自Mike的评论给出了同样的表现.

    char c[] = string.toCharArray();
    c[0] += 32;
    string = new String(c);
    
    Run Code Online (Sandbox Code Playgroud)
  4. test4用过StringBuilder.

    StringBuilder sb = new StringBuilder(string);
    sb.setCharAt(0, Character.toLowerCase(sb.charAt(0)));
    string = sb.toString();
    
    Run Code Online (Sandbox Code Playgroud)
  5. test5用了两个substring()电话.

    string = string.substring(0, 1).toLowerCase() + string.substring(1);
    
    Run Code Online (Sandbox Code Playgroud)
  6. 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();
    }
    
    Run Code Online (Sandbox Code Playgroud)

结论

如果String长度始终大于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);
}
Run Code Online (Sandbox Code Playgroud)

如果您确定您的文本将始终使用ASCII并且您正在寻找极端性能,因为您在瓶颈中找到了此代码,请使用test3.


Dan*_*cak 93

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

import java.beans.Introspector;

Assert.assertEquals("someInputString", Introspector.decapitalize("SomeInputString"));
Run Code Online (Sandbox Code Playgroud)

  • 从这个方法的文档:"这通常意味着将第一个字符从大写转换为小写,但在(不寻常)特殊情况下,当有多个字符并且第一个和第二个字符都是大写时,我们离开它一个人." (13认同)
  • 正是我所需要的。Introspector.decapitalize("ABC") 仍将是 ABC。WordUtils.uncapitalize("ABC") 生成“aBC”。只是分享前者是spring如何自动命名bean的,所以如果你需要通过bean名称检索ABCService,它不是aBCService,但仍然是ABCService。 (2认同)

Car*_*ada 20

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

  • 更具体地说,uncapitalize方法(java.lang.String)使用StringUtils还有一个额外的好处,就是不必担心代码中的NullPointerExceptions. (7认同)
  • 不一定是最有效的,但也许是最清楚的,这很重要. (3认同)
  • 取决于您要提高效率的资源-CPU或程序员时间:) (2认同)

Seb*_*ian 14

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

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

结果:someString

  • 这是一个很好的和干净的解决方案,但现在已经弃用了,我们应该使用commons-text's:`compile group:'org.apache.commons',name:'commons-text',version:'1.2'` (3认同)

Mic*_*zka 10

尽管采用了面向字母的方法,但我建议使用面向字符串的解 String.toLowerCase是特定于语言环境的,所以我会考虑这个问题.String.toLowerCase根据Character.toLowerCase更倾向于小写.另外一个面向char的解决方案不是完全兼容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;
    }
Run Code Online (Sandbox Code Playgroud)

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

System.out.println(uncapitalize("I", new Locale("TR","tr")));
System.out.println(uncapitalize("I", new Locale("DE","de")));
Run Code Online (Sandbox Code Playgroud)

将输出两个不同的结果:

一世

一世


Ala*_*nse 7

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

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