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

假设如下:

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

在分配 firstLetter的以下方法中,是否有可能影响性能的差异需要注意;

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

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

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);
}
}
}
}
283287 次浏览

长话短说,可能没关系,用你认为最好看的。

更详细的答案,特别是使用 Oracle 的 Java7 JDK,因为 JLS 中没有定义这一点:

String.valueOfCharacter.toString的工作原理是一样的,所以只要你觉得好看就用吧。事实上,Character.toString只是调用 String.valueOf(来源)。

所以问题是,你应该使用其中的一个还是 String.substring。再说一遍,这没什么大不了的。String.substring使用原始字符串的 char[],因此分配的对象少于 String.valueOf。这也可以防止原始字符串被 GC‘ ed,直到只有一个字符的字符串可用于 GC (这可能是内存泄漏) ,但是在您的示例中,它们在每次迭代之后都可用于 GC,所以这并不重要。保存的分配也无关紧要—— char[1]的分配成本很低,短期对象(单字符字符串)的分配成本对 GC 来说也很低。

如果你有一个足够大的数据集,这三个甚至是可测量的,substring将可能给一个 轻微的的优势。非常轻微。但是这个“如果... 可测量”包含了这个答案的真正关键: 为什么不试试这三个方法,然后测量哪一个是最快的呢?

从性能上看,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
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) + ".");
}
}
}
String whole = "something";
String first = whole.substring(0, 1);
System.out.println(first);
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 |
+----------------------------------------------------------------------+