Java 使字符串的第一个字符小写的最有效方法?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4052840/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 11:01:49  来源:igfitidea点击:

Most efficient way to make the first character of a String lower case?

javastringperformanceoptimization

提问by Andy

What is the most efficient way to make the first character of a Stringlower case?

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

I can think of a number of ways to do this:

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

Using charAt()with substring()

使用charAt()substring()

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

Or using a chararray

或者使用char数组

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


I am sure there are many other great ways to achieve this. What do you recommend?

我相信还有许多其他很棒的方法可以实现这一目标。你有什么建议吗?

采纳答案by Adam Stelmaszczyk

I tested the promising approaches using JMH. Full benchmark code.

我使用JMH测试了有前途的方法。完整的基准代码

Assumption during the tests (to avoid checking the corner cases every time): the input String length is always greater than 1.

测试期间的假设(避免每次都检查极端情况):输入字符串长度始终大于 1。

Results

结果

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

The score are operations per second, the more the better.

分数是每秒操作数,越多越好。

Tests

测试

  1. test1was first Andy's and Hllink's approach:

    string = Character.toLowerCase(string.charAt(0)) + string.substring(1);
    
  2. test2was second Andy's approach. It is also Introspector.decapitalize()suggested by Daniel, but without two ifstatements. First ifwas removed because of the testing assumption. The second one was removed, because it was violating correctness (i.e. input "HI"would return "HI"). This was almost the fastest.

    char c[] = string.toCharArray();
    c[0] = Character.toLowerCase(c[0]);
    string = new String(c);
    
  3. test3was a modification of test2, but instead of Character.toLowerCase(), I was adding 32, which works correctly if and only if the string is in ASCII. This was the fastest. c[0] |= ' 'from Mike's commentgave the same performance.

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

    StringBuilder sb = new StringBuilder(string);
    sb.setCharAt(0, Character.toLowerCase(sb.charAt(0)));
    string = sb.toString();
    
  5. test5used two substring()calls.

    string = string.substring(0, 1).toLowerCase() + string.substring(1);
    
  6. test6uses reflection to change char value[]directly in String. This was the slowest.

    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();
    }
    
  1. test1首先是 Andy 和 Hllink 的方法:

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

    char c[] = string.toCharArray();
    c[0] = Character.toLowerCase(c[0]);
    string = new String(c);
    
  3. test3是对 的修改test2,而不是Character.toLowerCase(),我添加了 32,当且仅当字符串为 ASCII 时,它才能正常工作。这是最快的。c[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使用反射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();
    }
    

Conclusions

结论

If the String length is always greater than 0, use test2.

如果字符串长度始终大于 0,请使用test2.

If not, we have to check the corner cases:

如果没有,我们必须检查极端情况:

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);
}

If you are sure that your text will be always in ASCII and you are looking for extreme performance because you found this code in the bottleneck, use test3.

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

回答by Alan Geleynse

Strings in Java are immutable, so either way a new string will be created.

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

Your first example will probably be slightly more efficient because it only needs to create a new string and not a temporary character array.

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

回答by Carlos Tasada

When it comes to string manipulation take a look to Jakarta Commons Lang StringUtils.

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

回答by Michael Konietzka

Despite a char oriented approach I would suggest a String oriented solution. String.toLowerCaseis Locale specific, so I would take this issue into account. String.toLowerCaseis to prefer for lower-caseing according to Character.toLowerCase. Also a char oriented solution is not full unicode compatible, because Character.toLowerCasecannot handle supplementary characters.

尽管采用面向字符的方法,我还是建议采用面向字符串的解决方案。 String.toLowerCase是 Locale 特定的,所以我会考虑这个问题。String.toLowerCase是根据Character.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;
    }

UPDATE:As an example how important the locale setting is let us lowercase Iin turkish and german:

更新:举个例子,语言环境设置有多重要,让我们I在土耳其语和德语中使用小写:

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

will output two different results:

将输出两种不同的结果:

?

i

?

一世

回答by Daniel Pacak

I came across a nice alternative if you don't want to use a third-party library:

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

import java.beans.Introspector;

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

回答by Peter Lamberg

If what you need is very simple (eg. java class names, no locales), you can also use the CaseFormatclass in the Google Guavalibrary.

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

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

Or you can prepare and reuse a converter object, which could be more efficient.

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

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

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

To better understand philosophy of the Google Guava string manipulation, check out this wiki page.

要更好地理解 Google Guava 字符串操作的原理,请查看此 wiki 页面

回答by Sebastian

If you want to use Apache Commons you can do the following:

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

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

Result: someString

结果:someString

回答by Bae Cheol Shin

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

回答by user3501758

I have come accross this only today. Tried to do it myself in the most pedestrian way. That took one line, tho longish. Here goes

我今天才遇到这个问题。试图以最行人的方式自己做。这花了一行,虽然很长。开始

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);

Gives:

给出:

Before str = TaxoRanks

在 str = TaxoRanks 之前

After str = taxoRanks

在 str = taxoRanks 之后

回答by Hllink

A very short and simple static method to archive what you want:

一个非常简短且简单的静态方法来归档您想要的内容:

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