Quand L'optimisation Javac StringBuilder/StringBuffer a-t-elle été introduite?

Je sais que le compilateur Javac est capable de transformer la concaténation de Chaînes + en utilisant StringBuilder/StringBuffer, et je suis curieux de savoir à partir de quelle version ce changement a été introduit?

J'utilise cet exemple de code:

public class Main {
  public static void main(String[] args) {
      String a = args[0];
      String s = "a";
      s = s + a;
      s = s + "b";
      s = s + "c";
      s = s + "d";
      s = s + "e";
      System.out.println(s);
  }
}

Jusqu'à présent, j'ai essayé avec javac 1.8.0_121, javac 1.6.0_20, javac 1.5.0_22 et java 1.4.2_19.

Voici un exemple du bytecode que je vois en utilisant javap -c de 1.4.2_19:

6:  astore_2
7:  new #3; //class StringBuffer
10: dup
11: invokespecial   #4; //Method java/lang/StringBuffer."<init>":()V
14: aload_2
15: invokevirtual   #5; //Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
18: aload_1
19: invokevirtual   #5; //Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
22: invokevirtual   #6; //Method java/lang/StringBuffer.toString:()Ljava/lang/String;

Les 4 versions semblent utiliser L'optimisation StringBuilder/StringBuffer, donc je suis curieux de savoir à partir de quelle version Javac ce changement a été introduit?

27
demandé sur Nicolas C 2017-02-27 17:15:13

4 réponses

Voici une citation de la spécification de langue de la version 1:

Une implémentation peut choisir d'effectuer la conversion et la concaténation en une seule étape pour éviter de créer puis de rejeter un objet intermédiaire String. Pour augmenter les performances de la concaténation répétée de chaînes, un compilateur Java peut utiliser la classe StringBuffer (§20.13) ou une technique similaire pour réduire le nombre d'objets intermédiaires String créés par l'évaluation d'un expression.

Retour à l'époque, ils avaient StringBuffer au lieu de StringBuilder.

Aussi une citation de StringBuffer de JDK1.0.2:

Cette classe est un tampon cultivable pour les caractères. Il est principalement utilisé pour créer des Chaînes. Le compilateur l'utilise pour implémenter l'opérateur"+".

30
répondu manouti 2017-02-27 14:28:17

J'ai regardé la spécification du langage Java, première édition (de 1996). Pas une trouvaille facile, mais ici c'est. Le passage sur l'optimisation de la concaténation était là même alors:

Une implémentation peut choisir d'effectuer la conversion et la concaténation en une seule étape pour éviter de créer puis de rejeter un objet de chaîne intermédiaire. Pour augmenter les performances de la concaténation répétée de chaînes, un compilateur Java peut utiliser la classe StringBuffer (§20.13) ou une classe similaire technique pour réduire le nombre d'objets de chaîne intermédiaires créés par l'évaluation d'une expression.

La spécification concernait alors StringBuffer, mais StringBuilder (auquel le libellé JLS actuel fait référence) pourrait être considéré comme plus performant car ses méthodes ne sont pas synchronisées.

Cela, cependant, ne signifie pas que l'on devrait compter sur l'optimisation comme Toujours étant en place. La concaténation de chaînes dans les boucles ne sera pas optimisée, par exemple.

11
répondu lukeg 2017-03-02 00:33:00

JLS a déjà été donné dans certaines réponses. Je veux juste faire le point que StringBuffer ( https://docs.oracle.com/javase/8/docs/api/java/lang/StringBuffer.html ) était là depuis 1.0 alors que

StringBuilder ( https://docs.oracle.com/javase/8/docs/api/java/lang/StringBuilder.html ) est venu dans la version 1.5. Veuillez consulter la section since: des javadocs respectifs.

5
répondu Shubham Chaurasia 2017-02-27 14:25:44

cela ne répond pas à la question, mais je veux simplement ajouter au point global que dans jdk-9 CE StringBuilder::append est l'une des stratégies autorisées, mais pas celle par défaut.

private enum Strategy {
   /**
    * Bytecode generator, calling into {@link java.lang.StringBuilder}.
    */
    BC_SB,

    /**
     * Bytecode generator, calling into {@link java.lang.StringBuilder};
     * but trying to estimate the required storage.
     */
    BC_SB_SIZED,

    /**
     * Bytecode generator, calling into {@link java.lang.StringBuilder};
     * but computing the required storage exactly.
     */
     BC_SB_SIZED_EXACT,

   /**
    * MethodHandle-based generator, that in the end calls into {@link java.lang.StringBuilder}.
    * This strategy also tries to estimate the required storage.
    */
    MH_SB_SIZED,

    /**
     * MethodHandle-based generator, that in the end calls into {@link java.lang.StringBuilder}.
     * This strategy also estimate the required storage exactly.
     */
    MH_SB_SIZED_EXACT,

    /**
     * MethodHandle-based generator, that constructs its own byte[] array from
     * the arguments. It computes the required storage exactly.
     */
     MH_INLINE_SIZED_EXACT
}

C'est en fait un bytecode invokedynamic pour la concaténation de chaînes, donc son implémentation est maintenant spécifique à JRE, pas au compilateur. La stratégie par défaut btw est: MH_INLINE_SIZED_EXACT

5
répondu Eugene 2017-02-28 19:09:50