web-dev-qa-db-fra.com

StringBuilder - Réinitialiser ou créer un nouveau

J'ai une condition qu'un StringBuilder continue de stocker des lignes correspondant à un modèle à partir d'un grand fichier plat (100 de Mo). Cependant, après avoir atteint une condition, j'écris le contenu du varialble StringBuilder dans un fichier texte.

Maintenant, je me demande si je devrais utiliser la même variable en réinitialisant l'objet ->

stringBuilder.delete(0,stringBuilder.length())

OR

stringBuilder=new StringBuilder();

Veuillez suggérer ce qui, selon vous, est le meilleur en ce qui concerne les problèmes de performances et de MOO.

22
Chandru

Je pense que StringBuilder#delete(start, end) est toujours un appel cher, vous devriez faire:

stringBuilder.setLength(0);

pour le réinitialiser.


MISE À JOUR: Après avoir consulté le code source de StringBuilder Il semble que setLength(int) laisse l'ancien tampon intact et il vaut mieux appeler: StringBuilder#trimToSize() après l'appel ci-dessus qui attempts to reduce storage used for the character sequence.

Donc, quelque chose comme ça serait plus efficace:

stringBuilder.setLength(0); // set length of buffer to 0
stringBuilder.trimToSize(); // trim the underlying buffer
32
anubhava

À mon humble avis, je suggère d'utiliser de nouveaux:

stringBuilder = new StringBuilder();

Je n'ai jamais entendu parler d'une fuite de mémoire dans StringBuilder, mais quand vous repoussez vraiment les limites, vous ne savez jamais. Je couvrirais mes paris contre elle en utilisant une nouvelle instance à chaque fois.

Dans le pire des cas, vous perdez peut-être une certaine efficacité et le GC obtient un entraînement, mais vous excluez la possibilité de MOO.

Pour cette raison, et également pour des raisons de clarté, je choisirais personnellement la nouvelle approche.

6
vikingsteve

Une différence fondamentale est que sb.delete conserve la référence, tandis que le constructeur la perd.

Si votre SB est un argument de méthode et est censé être utilisé pour renvoyer le contenu à l'appelant, vous devez utiliser sb.delete. L'appelant détient la référence d'origine.

5
user3241961

Eh bien, il y a une plus grande différence entre les deux. Le premier conserve la capacité qu'il avait avant de supprimer les caractères (c'est-à-dire stringBuilder.capacity()) tandis que le second crée un nouveau StringBuilder avec la capacité par défaut, 16. Bien sûr, vous pouvez simplement passer stringBuilder.capacity() comme argument pour le constructeur, mais il est important de comprendre la distinction ici, néanmoins.

Dans tous les cas, je doute fortement que vous constatiez une différence de performances substantielle entre ces deux variantes, alors choisissez celle qui est plus lisible et plus facile à gérer. niquement lorsque vous avez déterminé de manière concluante que cela provoque une sorte de goulot d'étranglement si vous changez d'approche.

3
arshajii

Idéalement, nous devrions utiliser new StringBuilder() Creuser un peu dans la classe StringBuilder de grepcode J'apprends ce qui suit.

Création d'un nouvel objet:

/**
     * Creates an AbstractStringBuilder of the specified capacity.
     */
    AbstractStringBuilder(int capacity) {
        value = new char[capacity];
    }

new StringBuilder () crée un nouvel objet avec un tableau de caractères de capacité initiale. Frais généraux ici: GC sera appelé pour effacer les objets plus anciens.

Utilisation de la suppression:

public AbstractStringBuilder delete(int start, int end) {
        if (start < 0)
            throw new StringIndexOutOfBoundsException(start);
        if (end > count)
            end = count;
        if (start > end)
            throw new StringIndexOutOfBoundsException();
        int len = end - start;
        if (len > 0) {
            System.arraycopy(value, start+len, value, start, count-end);
            count -= len;
        }
        return this;
    }

Utilisation de Length et TrimToSize:

public void trimToSize() {
        if (count < value.length) {
            value = Arrays.copyOf(value, count);
        }
    }

Appellera copyOf From classe de tableau

char statique public [] copyOf (char [] original, int newLength) {char [] copy = new char [newLength]; System.arraycopy (original, 0, copie, 0, Math.min (original.length, newLength)); copie de retour; }

Maintenant, il appellera également System.arrayCopy qui est une méthode native. Maintenant, si vous voyez dans copyOf, nous créons à nouveau un nouveau charArray de longueur 0, et lorsque nous essayons d'ajouter à nouveau des données, il appellera expand car la longueur actuelle serait 0 . Je pense donc qu'il vaut mieux appeler le nouveau StringBuilder ()

Vous pouvez voir le code ci-dessus sur grepcode

PS: @ user3241961 est écrit au cas où vous utilisez la référence de cet objet, alors new devrait le redéfinir

1
Akhil Dad

J'utiliserais:

 stringBuilder = new StringBuilder();

car si vous le remplissez avec une grande quantité de données, l'appel de stringBuilder.setLength(0); ne désallouera pas le tableau de sauvegarde, vous pouvez donc voir que l'utilisation de la mémoire reste élevée inutilement.

De plus, c'est juste plus facile à lire et à comprendre.

1
Bohemian

Il est moins coûteux de réutiliser l'objet créé que d'en allouer un nouveau, toujours. Cela évite également un travail supplémentaire pour le garbage collector, car vous ne gérez qu'un objet.

Le moyen le plus rapide est:

stringBuilder.setLength(0);
1
jmlotero

Si vous êtes dans une boucle serrée et que vous continuerez dans cette boucle après avoir écrit les données dans le fichier, vous devez certainement réutiliser le StringBuilder. Il n'y a aucune raison de ne pas le faire et c'est mieux que de baratiner le GC. Si vous écriviez cela en C ou C++, vous réutiliseriez le tampon.

De plus, bien qu'il soit vrai que la méthode delete (...) appelle System.arraycopy, le nombre d'octets copiés est égal à 0, c'est donc insignifiant.

Ah - quelqu'un d'autre m'a mentionné qu'il existe une méthode setLength (...) qui est le moyen le plus rapide de réutiliser le tampon.

0
jpayne