final ça marche comment déjà ?
Parlons un peu de comment on peut utiliser le mot clé final déjà. Il y a en gros 3 gros cas d'usage : sur une propriété/valeur, sur une méthode et sur une classe. Comme j'aime bien être logique on va en parler dans l'ordre inverse ! 😀
Sur une classe
En 3 mots : on interdit l'héritage.
class A {
}
final class B extends A {
}
class C extends B { // Erreur à la compilation
}
Sur une méthode
En 4 mots : on interdit la surcharge.
class A {
void m1() {}
final void m2() {}
}
class B extends A {
void m1() {} // OK
void m2() {} // Erreur à la compilation
}
Sur une propriété ou une valeur ou un paramètre
Ici aussi on va ajouter une restriction mais un peu plus subtile : on interdit la modification de la valeur. Attention par contre, pour le cas d'une primitive on va créer une constante mais pour un objet ce n'est pas le cas, on va seulement interdire d'affecter un nouvel objet à la référence.
class A {
final int a = 0;
final B b;
public A() {
this.b = new B();// commme b n'est pas initialisée sur la propriété
// comme a on est obligé de l'initialiser dans le constructeur
}
void m() {
this.a = 1;// Erreur à la compilation
this.b = new B();// Erreur à la compilation
this.b.c = 1;// OK car on ne change pas la référence de b
}
}
class A {
void m() {
final int a = 0;
final B b = new B();
a = 1;// Erreur à la compilation
b = new B();// Erreur à la compilation
b.c = 1;// OK car on ne change pas la référence de b
}
}
class A {
void m(int a, final int b, final C c) {
a = 1;// OK car pas de final
b = 1;// Erreur à la compilation
c = new C();// Erreur à la compilation
c.d = 1;// OK car on ne change pas la référence de c
}
}
Comme on peut le voir sur ces exemples, on a interdit une partie des possibilités d'écriture. Par contre on empêche pas de modifier une propriété d'un objet si la référence est final.
Quand utiliser final ?
Traditionnellement on dira qu'il y a deux cas d'utilisation : la conception ou l'efficacité.
On peut choisir d'interdire d'étendre une classe ou surcharger une méthode pour des questions de conception : d'un point de vue métier ça n'a aucun sens de pouvoir étendre cette classe ou surcharger cette méthode. C'est une bonne manière d'indiquer à votre successeur (ou à vous dans 6 mois) qu'il faut réfléchir avant de faire un héritage ou surcharger une méthode.
Dans le même temps utiliser des final sur des propriétés permet un très léger gain de performance (mais un léger gain + un léger gain + un léger gain, etc. ça fini par être un gros gain !) car le compilateur va garantir que le côté immuable induit par le final et optimiser le bytecode généré et ce sera aussi le cas au runtime avec des optimisations JVM. En effet de base le compilateur est obligé de partir du principe que vous allez modifier vos variables, mais avec un final il peut prendre des raccourcis et limiter certaines recopie inutiles.
De mon point de vue en plus du gain de performance, j'aime beaucoup utiliser des final sur les paramètres à des fins de documentation : si je mets un final sur un paramètre, ça veut dire que j'ai essayé de tendre vers une fonction pure (fonction qui ne va dépendre que des paramètres, ne pas les modifier et renvoyer un résultat qui est facilement testable) ou à minima fait l'effort d'indiquer ce qui ne changera pas parmi les paramètres. Dans le même temps le compilateur va m'aider à respecter ce contrat en me signalant que j'essaie de modifier un des paramètres. De la même façon que pour les propriétés on profite aussi ici d'un gain de performance, mais je trouve l'aspect documentaire plus fort.
Conclusion
Est-ce qu'on doit utiliser final ? Je dirais oui ! Est-ce que c'est grave de ne pas utiliser final ? clairement non, mais ce serait mieux de s'en servir.
Après on peut commencer par se forcer à utiliser final pour les zones des applications très utilisés pour profiter de tous les gains. Il faut voir qu'ajouter des final est généralement gratuit, donc on peut en ajouter au fil du temps, et que ça permet aussi de bien comprendre ce qu'on fait.
Crédit photo : https://pixabay.com/photos/computer-computer-code-programming-1873831/