web-dev-qa-db-fra.com

Performances entre String.format et StringBuilder

Pour concaténer String nous utilisons souvent StringBuilder au lieu de String + String, mais nous pouvons également faire de même avec String.format qui retourne la chaîne formatée selon les paramètres régionaux, le format et les arguments donnés.

Exemples:

Concaténer la chaîne avec StringBuilder

String concatenateStringWithStringBuilder(String name, String lName, String nick) {
    final StringBuilder sb = new StringBuilder("Contact {");
    sb.append(", name='").append(name)
      .append(", lastName='").append(lName)
      .append(", nickName='").append(nick)
      .append('}');
    return sb.toString();
}

Concaténer la chaîne avec StringFormat:

String concatenateStringWithStringFormat(String name, String lName, String nick) {
    return String.format("Contact {name=%s, lastName=%s, nickName=%s}", name, lName, nick);
}

En termes de performances, est String.Format aussi efficace que StringBuilder? Lequel est préférable de concaténer des chaînes et pourquoi?

[~ # ~] mise à jour [~ # ~]

J'ai vérifié le même question , mais ne répond pas à ma question. Jusqu'à présent, j'ai utilisé StringBuilder pour concaténer des chaînes, dois-je le suivre en utilisant? Ou dois-je utiliser String.format? la question est laquelle est la meilleure et pourquoi?

14
JUAN CALVOPINA M

Après avoir fait un petit test avec StringBuilder vs String.format J'ai compris combien de temps il faut à chacun pour résoudre la concaténation. Voici le code d'extrait et les résultats

Code:

String name = "stackover";
String lName = " flow";
String nick = " stackoverflow";
String email = "[email protected]";
int phone = 123123123;

//for (int i = 0; i < 10; i++) {
long initialTime1 = System.currentTimeMillis();
String response = String.format(" - Contact {name=%s, lastName=%s, nickName=%s, email=%s, phone=%d}",
                                name, lName, nick, email, phone);
long finalTime1 = System.currentTimeMillis();
long totalTime1 = finalTime1 - initialTime1;
System.out.println(totalTime1 + response);

long initialTime2 = System.currentTimeMillis();
final StringBuilder sb = new StringBuilder(" - Contact {");
sb.append("name=").append(name)
  .append(", lastName=").append(lName)
  .append(", nickName=").append(nick)
  .append(", email=").append(email)
  .append(", phone=").append(phone)
  .append('}');
String response2 = sb.toString();
long finalTime2 = System.currentTimeMillis();
long totalTime2 = finalTime2 - initialTime2;
System.out.println(totalTime2 + response2);
//}

Après avoir exécuté le code plusieurs fois, j'ai vu que String.format prend plus de temps:

String.format: 46: Contact {name=stackover, lastName= flow, nickName= stackoverflow, [email protected], phone=123123123}
StringBuilder: 0: Contact {name=stackover, lastName= flow, nickName= stackoverflow, [email protected], phone=123123123}
String.format: 38: Contact {name=stackover, lastName= flow, nickName= stackoverflow, [email protected], phone=123123123}
StringBuilder: 0: Contact {name=stackover, lastName= flow, nickName= stackoverflow, [email protected], phone=123123123}
String.format: 51: Contact {name=stackover, lastName= flow, nickName= stackoverflow, [email protected], phone=123123123}
StringBuilder: 0: Contact {name=stackover, lastName= flow, nickName= stackoverflow, [email protected], phone=123123123}

Mais si je lance le même code dans une boucle, le résultat change.

String.format: 43: Contact {name=stackover, lastName= flow, nickName= stackoverflow, [email protected], phone=123123123}
StringBuilder: 0: Contact {name=stackover, lastName= flow, nickName= stackoverflow, [email protected], phone=123123123}
String.format: 1: Contact {name=stackover, lastName= flow, nickName= stackoverflow, [email protected], phone=123123123}
StringBuilder: 0: Contact {name=stackover, lastName= flow, nickName= stackoverflow, [email protected], phone=123123123}
String.format: 1: Contact {name=stackover, lastName= flow, nickName= stackoverflow, [email protected], phone=123123123}
StringBuilder: 0: Contact {name=stackover, lastName= flow, nickName= stackoverflow, [email protected], phone=123123123}

La première fois String.format s'exécute, cela prend plus de temps, après quoi le temps est plus court même s'il ne devient pas constant en raison de StringBuilder

Comme l'a dit @ G.Fiedler: "String.format doit analyser la chaîne de format ... "

Avec ces résultats, on peut dire que StringBuilder est plus efficace queString.format

6
JUAN CALVOPINA M

Ce qui est "mieux" dépend uniquement de vos besoins:

  • Par exemple, String Builder Sera plus rapide, mais le code sera beaucoup plus illisible et il serait plus facile de faire une erreur.

  • D'autre part, String.format() produit un code plus lisible au détriment des performances.

Benchmark JMH pour illustrer la différence de performance (notez que le code du générateur de chaîne est plus long et très difficile à comprendre à quoi ressemblerait la chaîne résultante):

@Fork(1)
@State(Scope.Benchmark)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@Measurement(iterations = 10)
@Warmup(iterations = 10)
@BenchmarkMode(Mode.Throughput)
public class StringFormatBenchmark {
    private String name = "UserName";
    private String lName = "LUserName";
    private String nick = "UserNick";

    @Benchmark
    public void stringFormat(Blackhole blackhole) {
        final String result = String.format("Contact {name=%s, lastName=%s, nickName=%s}", name, lName, nick);
        blackhole.consume(result);
    }

    @Benchmark
    public void stringBuilder(Blackhole blackhole) {
        final StringBuffer sb = new StringBuffer("Contact {");
        sb.append(", name='").append(name)
                .append(", lastName='").append(lName)
                .append(", nickName='").append(nick)
                .append('}');
        final String result = sb.toString();
        blackhole.consume(result);
    }
}

Et les résultats:

Benchmark                             Mode  Cnt      Score     Error   Units
StringFormatBenchmark.stringBuilder  thrpt   10  10617.210 ± 157.302  ops/ms
StringFormatBenchmark.stringFormat   thrpt   10    960.658 ±   7.398  ops/ms

Pour le code non critique pour les performances, je préfère utiliser la fonction String.format(), car elle est plus facile et plus agréable à utiliser. Il est également visible à quoi ressemblerait la chaîne résultante, en regardant simplement le motif. Si je fais un code de performance critique, ou quelque chose qui doit avoir un faible impact GC, j'utiliserais un StringBuilder parce qu'il est plus rapide et peut être réutilisé.

17
Svetlin Zarev

StringBuilder est plus rapide, car String.format doit analyser la chaîne de format (une langue spécifique au domaine complexe). Et c'est cher.

StringBuilder au lieu de String + String

BTW: C'est la même chose, car il en résulte le même code d'octet (depuis Java 1.5).

8
G. Fiedler