jeudi 3 juillet 2008

Manipulation des chaines de caractères et performances en Java

En Java, dans des programmes qui doivent manipuler, analyser et traiter des chaines de caractères, la manière de coder peut avoir un gros impact sur les performances. Quelques éléments clé à prendre en compte :
  1. Une String est un objet immuable. Elle peut être utilisée en parallèle par plusieurs Threads simultanément en toute sécurité. Il est donc inutile de copier une chaine de caractère en faisant new String(s).
  2. Inutile de sortir systématiquement vos chaines de caractères comme des constantes, le compilateur le fait pour vous !
  3. Une chaine de caractère contient un char[]. Les opérations de type substring() sont très peu couteuses en mémoire ou en CPU puisqu'il n'y a pas copie de ce tableau mais simplement création d'un nouvel objet String qui pointe vers le même tableau.
  4. A la compilation, une concaténation de chaines de caractères "toto" + "titi" est automatiquement remplacée par la création d'un StringBuilder. Cette classe existe depuis le JDK 1.5 et est bien plus performante que la classe StringBuffer. L'API est la même mais il n'y a pas de synchronized (a ne pas utiliser en accès multithread donc). Donc remplacer dans une méthode les concaténation de chaine par des StringBuffer comme on le recommandait il y a quelques années fait désormais baisser les performances !
  5. Un StringBuilder ou un StringBuffer contient lui aussi un char[] dont la taille par défaut est 16. Dès que le buffer est plein, le char[] est automatiquement remplacé par un char deux fois plus grand dans lequel le premier est copié. Bien dimensionner le buffer à l'origine peut donc économiser pas mal d'opérations de copie.
  6. L'appel de la méthode toString() d'un StringBuilder ou d'un StringBuffer déclenche la copie du char[] qu'il contient. Ne pas faire writer.append(stringBuffer.toString()) mais plutôt directement writer.append(stringBuffer) permet d'éviter une opération de copie.
  7. Toutes les opérations de type replace() ou replaceall() déclenchent des copies du tableau.
  8. On peut exécuter des recherches et des remplacements directement sur des StringBuffer sans faire de toString() de la manière suivante :
    stringBuilder=Pattern.compile("expr").matcher("stringBuilder").replaceAll("newvalue"); On économise ainsi une copie.

Ne pas hésiter à décompiler les classes String et StringBuilder pour bien comprendre comment tout ça fonctionne. C'est très instructif et ça aide beaucoup à optimiser le code.

Aucun commentaire: