web-dev-qa-db-fra.com

Quel est le meilleur moyen d'obtenir la première lettre d'une chaîne en Java, renvoyée sous la forme d'une chaîne de longueur 1?

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);
            }
        }
  }
}
66
Adrian Torrie

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
105
Ankur Lathi

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?

13
yshavit
String whole = "something";
String first = whole.substring(0, 1);
System.out.println(first);
6
MIk.13
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 |
+----------------------------------------------------------------------+
1
Nikita