从Java字符串中以长度1的字符串返回的第一个字母的最佳方法是什么?


72

假设以下内容:

String example      = "something";
String firstLetter  = "";

以下分配方式firstLetter可能会影响性能,请注意是否存在差异;哪个最好,为什么?

firstLetter = String.valueOf(example.charAt(0));
firstLetter = Character.toString(example.charAt(0));
firstLetter = example.substring(0, 1);

返回第一个字母为a的原因String是,这是在Hadoop中运行的,并且需要将字符串分配给Text类型,该字符串将从方法中firstLetter输出为a ,例如:keymap()

public class FirstLetterMapper extends Mapper<LongWritable, Text, Text, IntWritable> {
    String line = new String();
    Text firstLetter = new Text();
    IntWritable wordLength = new IntWritable();

    @Override
    public void map(LongWritable key, Text value, Context context)
            throws IOException, InterruptedException {

        line = value.toString();

        for (String word : line.split("\\W+")){
            if (word.length() > 0) {

                // ---------------------------------------------
                // firstLetter assignment
                firstLetter.set(String.valueOf(word.charAt(0)).toLowerCase());
                // ---------------------------------------------

                wordLength.set(word.length());
                context.write(firstLetter, wordLength);
            }
        }
  }
}

Answers:


115

substring(0, 1)通过执行以下操作,可以发现性能更好:

    String example = "something";
    String firstLetter  = "";

    long l=System.nanoTime();
    firstLetter = String.valueOf(example.charAt(0));
    System.out.println("String.valueOf: "+ (System.nanoTime()-l));

    l=System.nanoTime();
    firstLetter = Character.toString(example.charAt(0));
    System.out.println("Character.toString: "+ (System.nanoTime()-l));

    l=System.nanoTime();
    firstLetter = example.substring(0, 1);
    System.out.println("substring: "+ (System.nanoTime()-l));

输出:

String.valueOf: 38553
Character.toString: 30451
substring: 8660

15
这是事实,但我觉得更合适的计时方法将涉及多次执行此测试,而不是上面的代码所隐含的一次。请在gist.github.com/micahjsmith/c7c9d31b342c115aef90上查看我的测试代码。在GNU / Linux上运行Java 1.7,我发现上面显示的三种方法之间没有区别,并且如果有的话,String.valueOf的性能比我看到的最好。(尽管运行之间存在一些差异。)这使我倾向于相信下面的@yshavit对这个问题有更适用的回答。
米卡·史密斯

14

长话短说,这可能并不重要。使用您认为最好的任何一种。

更长的答案,特别是使用Oracle的Java 7 JDK,因为在JLS上没有定义:

String.valueOfCharacter.toString以相同的方式工作,因此请使用您觉得更好的任何一种。实际上,Character.toString只需调用String.valueOfsource)。

所以问题是,您应该使用其中之一还是String.substring。再次在这里没什么大不了的。String.substring使用原始字符串char[],因此分配的对象少于String.valueOf。这还可以防止原始字符串被GC处理,直到一个字符的字符串可用于GC(这可能是内存泄漏)为止,但是在您的示例中,它们在每次迭代后都可用于GC,因此不会没关系 您保存的分配也无关紧要char[1]-a分配便宜,而寿命短的对象(就像一个字符的字符串一样)对GC也很便宜。

如果您有足够大的数据集,甚至三个都可以测量,那么substring可能会略有优势。喜欢,真的很轻微。但是,“如果...可测量”包含了此答案的真正关键:为什么不尝试全部三个,然后测量哪个是最快的?


10
String whole = "something";
String first = whole.substring(0, 1);
System.out.println(first);

这并没有添加任何内容,因为此代码已在原始问题中提出,并在迄今为止的所有答案中得到了进一步扩展。
阿德里安·托里

1
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.Warmup;

import java.util.concurrent.TimeUnit;

@State(Scope.Thread)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@Warmup(iterations = 5, time = 1)
@Fork(value = 1)
@Measurement(iterations = 5, time = 1)
public class StringFirstCharBenchmark {

    private String source;

    @Setup
    public void init() {
        source = "MALE";
    }

    @Benchmark
    public String substring() {
        return source.substring(0, 1);
    }

    @Benchmark
    public String indexOf() {
        return String.valueOf(source.indexOf(0));
    }
}

结果:

+----------------------------------------------------------------------+
| Benchmark                           Mode  Cnt   Score   Error  Units |
+----------------------------------------------------------------------+
| StringFirstCharBenchmark.indexOf    avgt    5  23.777 ? 5.788  ns/op |
| StringFirstCharBenchmark.substring  avgt    5  11.305 ? 1.411  ns/op |
+----------------------------------------------------------------------+

-6
import java.io.*;
class Initials {

    public static void main(String args[]) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String s;
        char x;
        int l;
        System.out.print("Enter any sentence: ");
        s = br.readLine();
        s = " " + s; //adding a space infront of the inputted sentence or a name
        s = s.toUpperCase(); //converting the sentence into Upper Case (Capital Letters)
        l = s.length(); //finding the length of the sentence
        System.out.print("Output = ");

        for (int i = 0; i < l; i++) {
            x = s.charAt(i); //taking out one character at a time from the sentence
            if (x == ' ') //if the character is a space, printing the next Character along with a fullstop
                System.out.print(s.charAt(i + 1) + ".");
        }
    }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.