Question

String s = "";
for(i=0;i<....){
    s = some Assignment;
}

ou

for(i=0;i<..){
    String s = some Assignment;
}

Je n’ai plus besoin de sortir de la boucle. La première option est peut-être préférable, car une nouvelle chaîne n'est pas initialisée à chaque fois. La seconde aurait toutefois pour effet de limiter la portée de la variable à la boucle elle-même.

EDIT: En réponse à la réponse de Milhous. Il serait inutile d'affecter la chaîne à une constante dans une boucle, n'est-ce pas? Non, ici, 'une affectation' signifie une valeur changeante obtenue à partir de la liste itérée à travers.

De plus, la question ne vient pas parce que je suis inquiet pour la gestion de la mémoire. Je veux juste savoir lequel est le meilleur.

Était-ce utile?

La solution

La portée limitée est la meilleure

Utilisez votre deuxième option:

for ( ... ) {
  String s = ...;
}

La portée n'affecte pas les performances

Si vous désassemblez le code compilé à partir de chacun (à l'aide de l'outil javap du JDK), vous verrez que la boucle est compilée selon les mêmes instructions JVM dans les deux cas. Notez également que Brian R. Bondy " Option 3 " est identique à l'option n ° 1. Aucun élément supplémentaire n'est ajouté ou supprimé de la pile lorsque vous utilisez l'étendue plus étroite, et les mêmes données sont utilisées dans la pile dans les deux cas.

Éviter l'initialisation prématurée

La seule différence entre les deux cas est que, dans le premier exemple, la variable s est inutilement initialisée. Il s'agit d'un problème distinct de l'emplacement de la déclaration de variable. Cela ajoute deux instructions inutiles (pour charger une constante de chaîne et la stocker dans un emplacement de pile). Un bon outil d'analyse statique vous avertira que vous ne lisez jamais la valeur que vous affectez à s , et un bon compilateur JIT l'éludera probablement au moment de l'exécution.

Vous pouvez résoudre ce problème simplement en utilisant une déclaration vide (c'est-à-dire, String s; ), mais cela est considéré comme une mauvaise pratique et a un autre effet secondaire discuté ci-dessous.

Souvent, une valeur fictive telle que null est affectée à une variable simplement pour masquer une erreur du compilateur selon laquelle une variable est lue sans être initialisée. Cette erreur peut être considérée comme un indice que la portée de la variable est trop grande et qu'elle est déclarée avant d'avoir besoin de recevoir une valeur valide. Les déclarations vides vous obligent à considérer chaque chemin de code; N'ignorez pas cet avertissement précieux en attribuant une valeur fictive.

Conserver les emplacements de pile

Comme mentionné, bien que les instructions JVM soient les mêmes dans les deux cas, il existe un effet secondaire subtil qui rend préférable, au niveau de la JVM, d’utiliser la portée la plus limitée possible. Cela est visible dans la " table de variables locales " pour la méthode. Pensez à ce qui se passe si vous avez plusieurs boucles, avec les variables déclarées dans une étendue inutilement grande:

void x(String[] strings, Integer[] integers) {
  String s;
  for (int i = 0; i < strings.length; ++i) {
    s = strings[0];
    ...
  }
  Integer n;
  for (int i = 0; i < integers.length; ++i) {
    n = integers[i];
    ...
  }
}

Les variables s et n peuvent être déclarées à l'intérieur de leurs boucles respectives, mais comme elles ne le sont pas, le compilateur utilise deux "slots". dans le cadre de la pile. S'ils ont été déclarés à l'intérieur de la boucle, le compilateur peut réutiliser le même emplacement, réduisant ainsi le cadre de la pile.

Ce qui compte vraiment

Cependant, la plupart de ces problèmes sont sans importance. Un bon compilateur JIT verra qu'il n'est pas possible de lire la valeur initiale que vous affectez inutilement et d'optimiser l'affectation. Enregistrer un créneau ici ou dans un autre cas ne fera pas ou ne cassera pas votre candidature.

L'important est de rendre votre code lisible et facile à gérer. À cet égard, il est nettement préférable d'utiliser une portée limitée. Plus la portée d'une variable est petite, plus il est facile de comprendre comment elle est utilisée et quel impact auront les modifications apportées au code.

Autres conseils

En théorie , déclarer une chaîne dans la boucle est une perte de ressources. Dans la pratique , toutefois, les deux extraits que vous avez présentés seront compilés avec le même code (déclaration en dehors de la boucle).

Ainsi, si votre compilateur effectue une optimisation quelconque, il n'y a pas de différence.

En général, je choisirais le second, car la portée de la variable 's' est limitée à la boucle. Avantages:

  • C'est mieux pour le programmeur car vous n'avez pas à vous soucier de son utilisation ultérieure quelque part dans la fonction
  • Cela convient mieux au compilateur, car la portée de la variable est plus petite et peut donc potentiellement faire plus d’analyses et d’optimisations
  • Ceci est préférable pour les futurs lecteurs car ils ne se demanderont pas pourquoi la variable 's' est déclarée en dehors de la boucle si elle n'est jamais utilisée plus tard

Si vous souhaitez accélérer les boucles, je préfère déclarer une variable max à côté du compteur afin qu'aucune recherche répétée de la condition ne soit nécessaire:

au lieu de

for (int i = 0; i < array.length; i++) {
  Object next = array[i];
}

je préfère

for (int i = 0, max = array.lenth; i < max; i++) {
  Object next = array[i];
}

Toutes les autres choses qui devraient être considérées ont déjà été mentionnées, donc juste mes deux sous (voir l'article d'Erickson)

Greetz, GHad

Pour ajouter un peu à @ Esteban Araya , ils nécessiteront tous les deux la création d'une nouvelle chaîne à travers la boucle (en tant que valeur de retour de l'expression some Assignment ). Ces chaînes doivent être ramassées dans un sens ou dans l’autre.

Je sais que c'est une vieille question, mais je pensais ajouter un peu qui est légèrement lié.

Lors de la navigation dans le code source Java, j'ai remarqué que certaines méthodes, telles que String.contentEquals (dupliquée ci-dessous) généraient des variables locales redondantes qui n'étaient que des copies de variables de classe. Je crois qu’il ya eu un commentaire quelque part qui impliquait que l’accès aux variables locales était plus rapide que l’accès aux variables de classe.

Dans ce cas, "v1" et " v2 " sont apparemment inutiles et pourraient être éliminés pour simplifier le code, mais ont été ajoutés pour améliorer les performances.

public boolean contentEquals(StringBuffer sb) {
    synchronized(sb) {
        if (count != sb.length())
            return false;
        char v1[] = value;
        char v2[] = sb.getValue();
        int i = offset;
        int j = 0;
        int n = count;
        while (n-- != 0) {
            if (v1[i++] != v2[j++])
                return false;
        }
    }
    return true;
}

Il me semble que nous avons besoin de plus de précisions sur le problème.

Le

s = some Assignment;

n’est pas spécifié quant au type d’affectation dont il s’agit. Si l'affectation est

s = "" + i + "";

alors une nouvelle piqûre doit être allouée.

mais si c'est

s = some Constant;

s indiquera simplement l'emplacement de la mémoire des constantes. La première version serait donc plus efficace en termes de mémoire.

Il semble que je ne sois pas bête de me soucier de l’optimisation d’une boucle for pour un IMHO de langue interprétée.

Lorsque j’utilise plusieurs threads (plus de 50), j’ai trouvé que c’était un moyen très efficace de gérer les problèmes de threads fantômes avec le fait de ne pas pouvoir fermer un processus correctement. Si je me trompe, veuillez laisser moi savoir pourquoi je me trompe:

Process one;
BufferedInputStream two;
try{
one = Runtime.getRuntime().exec(command);
two = new BufferedInputStream(one.getInputStream());
}
}catch(e){
e.printstacktrace
}
finally{
//null to ensure they are erased
one = null;
two = null;
//nudge the gc
System.gc();
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top