Supposons ce qui suit:
String example = "something";
String firstLetter = "";
Existe-t-il des différences à connaître avec les manières suivantes d’affecter firstLetter
qui pourraient avoir une incidence sur les performances; qui serait le meilleur et pourquoi?
firstLetter = String.valueOf(example.charAt(0));
firstLetter = Character.toString(example.charAt(0));
firstLetter = example.substring(0, 1);
La raison pour laquelle la première lettre est renvoyée en tant que String
est qu’elle est exécutée dans Hadoop et qu’une chaîne est nécessaire pour l’affecter à un type Text
, firstLetter
sera affiché en tant que key
à partir d'une méthode map()
, par exemple:
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);
}
}
}
}
En ce qui concerne les performances, substring(0, 1)
est préférable, comme suit:
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));
Sortie:
String.valueOf: 38553
Character.toString: 30451
substring: 8660
Longue histoire courte, ce n'est probablement pas grave Utilisez celui qui vous semble le plus joli.
Réponse plus longue, en utilisant le JDK Java 7 d'Oracle, car il n'est pas défini dans le JLS:
String.valueOf
ou Character.toString
fonctionnent de la même manière, utilisez donc celui qui vous semble le plus agréable. En fait, Character.toString
appelle simplement String.valueOf
( source ).
La question est donc de savoir si vous devez utiliser l’un de ceux-ci ou String.substring
. Là encore, peu importe. String.substring
utilise la chaîne d'origine char[]
et alloue ainsi un objet de moins que String.valueOf
. Cela empêche également la chaîne d'origine d'être GC'ed jusqu'à ce que la chaîne à un caractère soit disponible pour GC (ce qui peut être une fuite de mémoire), mais dans votre exemple, ils seront tous deux disponibles pour GC après chaque itération. Peu importe. L'affectation que vous enregistrez importe également: un char[1]
est peu coûteux à allouer, et les objets éphémères (comme le sera la chaîne à un caractère) sont également abordables pour GC.
Si vous avez un ensemble de données suffisamment grand pour que les trois soient même mesurables, substring
donnera probablement un léger Edge. Comme, vraiment léger. Mais ce "si ... mesurable" contient la vraie clé de cette réponse: pourquoi ne pas simplement essayer les trois et mesurer lequel est le plus rapide?
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));
}
}
Résultats:
+----------------------------------------------------------------------+
| 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 |
+----------------------------------------------------------------------+