Benchmarking et optimisations en Java
Quid des optimisations utiles ou carrément devenues légendaires
Cette partie propose une liste non-exhaustive des optimisations côté développeur, qui sont utiles ou carrément devenues légendaires.
Taille des identifiants
Légende cyberurbaine n°1 : la taille des variables influent sur les performances.

Le test consiste à accéder à une variable avec un nom long ou un nom court...Le résultat est des plus parlants, ça ne change rien du tout.
Conclusion : Aucune raison autre que religieuse à utiliser des abréviations compréhensibles des seuls initiés car le nom des variables est stocké dans un dictionnaire en tête du bytecode.
Gestion des exceptions
Légende cyberurbaine n°2 : la gestion des exceptions, c'est lent.
Là encore, la différence est flagrante, n'est-ce pas ?
Conclusion : Si votre programme broute, inutile de virer la gestion des exceptions. La génération de la stacktrace est coûteuse, mais pas tellement (0,07 ms pour une pile de 50 sur un pc récent). Elle est en réalité dumpée depuis le natif dans une structure javaesque ( le fichier source concerné est ThreadService.cpp).
Les entiers
Légende cyberurbaine n°3 : utiliser des byte, c'est mieux, ça prend moins de place et c'est plus rapide.C'est tout sauf juste, soit archi-faux. Pour les opérations de comptage, le byte est systématiquement un mauvais choix, les CPU manipulant des entiers de 32 ou 64 bits.
Pour appuyer nos propos, la comparaison entre le bytecode pour incrémenter un int et un byte est très explicite.
Pour un int :
IINC 1: i 1
Pour un byte :
ILOAD 1: b
ICONST_1
IADD
I2B
ISTORE 1: b
Conclusion : Les int sont vos amis.
Utilisation du mot-clé final
Légende cyberurbaine n°4 : mettez final, ça va plus vite !
Et oui, ça n'améliore pas des masses le résultat, je vous laisse deviner qui est le coupable.
Conclusion : final est
indispensable pour le design du code, mais HotSpot optimise
ça dynamiquement !
Condition d'une boucle
Légende
cyberurbaine n°5 : Bonnes performances et bon
sens vont de paire !
Et c'est VRAI !
Premier code :
for(int i = 0; i < calculeValeurMax(); i++){
...
}
Cette version n'est pas géniale puisqu'on appelle calculeValeurMax() à chaque itération.
Deuxième code :
for(int i = calculeValeurMax() - 1; i >=0; i--){
...
}
C'est beaucoup mieux, on aurait également pu penser à stocker le résultat de l'appel à calculValeurMax() avant de démarrer la boucle.

Conclusion : il faut systématiquement passer par un BufferedInputStream/BufferedOutputStream. Les NIO offrent de meilleures performances, mais au prix d'un code plus complexe.
Et c'est VRAI !
Premier code :
for(int i = 0; i < calculeValeurMax(); i++){
...
}
Cette version n'est pas géniale puisqu'on appelle calculeValeurMax() à chaque itération.
Deuxième code :
for(int i = calculeValeurMax() - 1; i >=0; i--){
...
}
C'est beaucoup mieux, on aurait également pu penser à stocker le résultat de l'appel à calculValeurMax() avant de démarrer la boucle.
Entrées / Sorties
Règle d'or: Pour une bonne hygiène de code, pensez au tampon.
Conclusion : il faut systématiquement passer par un BufferedInputStream/BufferedOutputStream. Les NIO offrent de meilleures performances, mais au prix d'un code plus complexe.