IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage Java Discussion :

Javac utilise la classe Stringbuilder ?


Sujet :

Langage Java

  1. #1
    Membre expert

    Avatar de Songbird
    Homme Profil pro
    Bidouilleur
    Inscrit en
    Juin 2015
    Messages
    493
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 25
    Localisation : France

    Informations professionnelles :
    Activité : Bidouilleur
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Juin 2015
    Messages : 493
    Points : 3 872
    Points
    3 872
    Billets dans le blog
    8
    Par défaut Javac utilise la classe Stringbuilder ?
    Bonjour,

    Je suis tombé sur un topic (tardivement, je sais ) posté sur Stackoverflow qui expliquait qu'il était inutile d'utiliser un objet Stringbuilder pour créer de longues chaînes de caractères puisque le compilateur le fait tout seul.

    Seulement: de quel compilateur il est question ? Javac ? le compilo JIT ?

    Car moi après avoir fait un petit test de mon côté, on remarque clairement dans le bytecode qu'il n'utilise absolument rien:
    Code java : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     
    class myapp {
      public myapp();
        Code:
           0: aload_0
           1: invokespecial #1                  // Method java/lang/Object."<init>":()V
           4: return
     
      public static void main(java.lang.String...);
        Code:
           0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
           3: ldc           #3                  // String HellomynameisJohnHellomynameisJohnHellomynameisJohn
           5: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
           8: return
    }

    J'ai compilé mon code source sous Java 8.

    Quelqu'un saurait m'expliquer ?

    Je vous remercie d'avance pour vos réponses !
    Avant de poster: FAQ Rust; FAQ Dart; FAQ Java; FAQ JavaFX.
    Vous souhaiteriez vous introduire au langage Rust ? C'est par ici ou ici !
    Une question à propos du langage ? N'hésitez pas à vous rendre sur le forum !


    Pour contribuer à la rubrique, vous pouvez me contacter par MP (Sorry, we're closed!) ou contacter directement la rédaction.

  2. #2
    Expert éminent sénior
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Points : 23 190
    Points
    23 190
    Billets dans le blog
    1
    Par défaut
    Salut,



    Il faudrait voir le code que tu as compilé et le post en question sur Stackoverflow.
    javac utilise bien StringBuilder pour la concaténation, mais la réponse à ta question n'est pas aussi simple...

    Il peut être faux de dire qu'il ne faut pas utiliser StringBuilder, comme il peut être faux de dire qu'il faut l'utiliser.
    Tout dépend de ce que fais ton code.





    A l'origine le problème survient avec ce genre de code qui utilise l'opérateur + (ou +=) pour ajouter des éléments dans une String via une boucle :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    	public static String buildABigString(int max) {
    		String s = "0";
    		for (int i=1; i<=max; i++) {
    			s += "," + i; // ou		s = s + "," + i;
    		}
    		return s;
    	}
    Le code semble correct et compile bien, mais il a un coût exponentielle avec l'augmentation du nombre d'itération.
    (sur mon poste cela prend plus de 3.5 secondes pour max=50_000, et il a tourné des minutes pour max=500_000 avant que je ne le coupe).

    Cela vient indirectement du fait que le compilateur remplace l'opérateur +/+= par un StringBuilder, dans ce cas avec quelque chose équivalent à ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    	public static String buildABigString(int max) {
    		String s = "0";
    		for (int i=1; i<=max; i++) {
    			s = new StringBuilder(s)
    				.append(",")
    				.append(i)
    				.toString();
    		}
    		return s;
    	}
    En gros à chaque itération cela crée un StringBuilder contenant une copie de 's', on lui ajoute des éléments, et on crée une String comme résultat qu'on affecte à 's'.
    Bref à chaque itération on crée deux objets temporaires de plus en plus gros, ce qui va donner beaucoup de travail au GC...


    Pourtant StringBuilder est optimisé pour de tel traitement. C'est juste qu'il est très mal utilisé : il faut utiliser un seul StringBuilder pour tout le traitement.
    Il faut donc utiliser explicitement le StringBuilder puisque le compilateur ne peut pas le faire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    	public static String buildABigString(int max) {
    		StringBuilder sb = new StringBuilder("0");
    		for (int i=1; i<=max; i++) {
    			sb.append(",").append(i);
    		}
    		return sb.toString();
    	}
    Ce code me prend 30ms pour max=500_000... et il me faut monter à max=25_000_000 pour dépasser la seconde...





    Du coup il est conseillé d'utiliser StringBuilder à la place de l'opérateur + ou += dans une boucle.





    Problème : certains comprennent mal ce principe, et remplace TOUTES les concaténations par un StringBuilder.
    Or c'est contre productif.

    Par exemple si on prend le code suivant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    	public String hello(String name) {
    		return "hello " + name;
    	}
    il sera compilé en quelque chose comme ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    	public String hello(String name) {
    		return new StringBuilder("hello ").append(name).toString();
    	}
    Dans ce cas précis il est inutile d'utiliser explicitement StringBuilder ici, car cela ne ferait que rendre le code moins lisible.

    Pire : le compilateur peut optimiser cela si on concatène des constantes, ainsi par exemple si on prend le code suivant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    	public static final String WORD_SEPARATOR = " "; 
     
    	public String hello(String name) {
    		return "hello" + WORD_SEPARATOR + name;
    	}
    Le compilateur va pouvoir "préconcaténer" "hello" + WORD_SEPARATOR (car il s'agit de constante connu à la compilation), afin de générer un code identique à l'exemple précédent.
    Il peut même supprimer complètement le StringBuilder si toute la concaténation peut être déduite à la compilation (et je suppose que c'est ce que tu as fait dans ton code pour ne pas voir le StringBuilder avec javap).

    Il est inutile d'utiliser StringBuilder sur un concaténation en ligne, car l'opérateur + est plus lisible et plus efficace.




    Bref en gros :
    • sur une ligne, il est préférable d'utiliser l'opérateur +.
    • pour des concaténations plus conséquentes (dans une boucle par ex), il est préférable d'utiliser StringBuilder.






    A noter enfin que Java 9 va probablement changer cela et remplacera l'utilisation directe de StringBuilder par l'appel une méthode dynamique.
    Cela devrait permettre d’optimiser un peu plus la concaténation...


    a++

  3. #3
    Membre expert

    Avatar de Songbird
    Homme Profil pro
    Bidouilleur
    Inscrit en
    Juin 2015
    Messages
    493
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 25
    Localisation : France

    Informations professionnelles :
    Activité : Bidouilleur
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Juin 2015
    Messages : 493
    Points : 3 872
    Points
    3 872
    Billets dans le blog
    8
    Par défaut
    Salut,

    Merci pour ta réponse des plus complètes.


    (et je suppose que c'est ce que tu as fait dans ton code pour ne pas voir le StringBuilder avec javap).
    Oui alors effectivement ça doit venir de ça, voici le code source:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
     
    class myapp
    {
        //Oui je sais ma classe ne commence pas par une majuscule
        public myapp()
        {
     
        }
     
     
        public static void main(String... args)
        {
            System.out.println("Hello"+"my"+"name"+"is"+"John"+"Hello"+"my"+"name"+"is"+"John"+"Hello"+"my"+"name"+"is"+"John");
        }
     
     
    }
    D'où le:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    3: ldc           #3                  // String HellomynameisJohnHellomynameisJohnHellomynameisJohn
    Par contre je ne me rappelle plus du nom du topic sur StackOverflow (cf. l'heure à laquelle j'ai posé ma question)



    En tout cas merci encore, ça m'a permis de comprendre un peu mieux le comportement du compilateur vis-à-vis des chaînes de caractères et de la concaténation.

    Bonne soirée !
    Avant de poster: FAQ Rust; FAQ Dart; FAQ Java; FAQ JavaFX.
    Vous souhaiteriez vous introduire au langage Rust ? C'est par ici ou ici !
    Une question à propos du langage ? N'hésitez pas à vous rendre sur le forum !


    Pour contribuer à la rubrique, vous pouvez me contacter par MP (Sorry, we're closed!) ou contacter directement la rédaction.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 8
    Dernier message: 31/10/2007, 17h28
  2. [Taglibs] Utiliser les classes css ?
    Par PeteMitchell dans le forum Struts 1
    Réponses: 4
    Dernier message: 05/05/2007, 01h31
  3. utilisation de CLASS dans un formulaire
    Par lepierre dans le forum Balisage (X)HTML et validation W3C
    Réponses: 3
    Dernier message: 18/11/2004, 16h38
  4. utiliser des classes dont on n'a pas le source
    Par kocin dans le forum Eclipse Java
    Réponses: 2
    Dernier message: 28/08/2004, 16h05
  5. [Debutant] probleme pour utiliser les classes d'un .jar
    Par pissek dans le forum Eclipse Java
    Réponses: 3
    Dernier message: 12/05/2004, 18h21

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo