Pourquoi le mot-clé «final» est-il si peu utilisé dans l'industrie? [fermé]

14

Depuis que j'ai découvert les pouvoirs du finalmot clé en Java il y a quelques années, cela m'a aidé à rendre mes codes beaucoup plus lisibles, car les gens peuvent facilement voir ce que sont les variables en lecture seule. Cela peut également donner un petit coup de pouce au JIT, et bien que ce soit très limité, cela ne peut pas nuire, en particulier lors du ciblage d'appareils intégrés tels que les plates-formes Android.

Mais plus que tout, il contribue à rendre une conception plus robuste aux changements et à guider les autres committers lorsqu'ils ont besoin de modifier la base de code.

Cependant, en parcourant une partie du code source JDK, je ne suis jamais tombé sur ce mot clé, que ce soit pour les classes, les méthodes ou les variables. La même chose s'applique à divers systèmes que j'ai dû examiner.

Y a-t-il une raison? Est-ce un paradigme de conception commun de tout laisser mutable de l'intérieur?

Aurelien Ribon
la source
dans les micro-optimisations, la définition de finalchamps a la même sémantique que l'écriture d'un volatilechamp, puis leur lecture ultérieure doit avoir une sémantique de lecture volatile, ce n'est pas toujours ce que vous voulez
cliquet freak
5
@ratchet: Je pense qu'il s'agit davantage de rendre vos classes immuables, comme dans la programmation fonctionnelle.
Jonas
@Kwebble: Peut-être plus important encore, les instances de chaîne individuelles sont immuables.
MatrixFrog

Réponses:

9

Je soupçonne que la raison pour laquelle vous ne le voyez pas est que le JDK est conçu pour être étendu (c'est la base à partir de laquelle tous vos programmes sont construits). Il ne serait pas rare du tout que le code d'application s'en serve. Je ne m'attendrais pas non plus à en voir beaucoup dans le code de la bibliothèque non plus (car les bibliothèques sont souvent conçues pour l'extension également).

Essayez de jeter un œil à de bons projets open source et je pense que vous en trouverez plus.

Contrairement à ce que vous voyez en Java, dans le monde .NET, j'ai entendu l'argument à plusieurs reprises selon lequel les classes devraient être sealed(similaires à la finale appliquée à une classe) par défaut, et que le développeur devrait explicitement décocher il.

Steven Evers
la source
2
Je faisais même référence à de nombreux membres privés ou protégés de certaines classes JDK qui sont évidemment des variables d'objet "spawn once, never override". Particulièrement dans le package swing. Ce sont des candidats parfaits pour «final», car le remplacement par un pointeur nul entraînerait des erreurs lors de l'utilisation des composants.
Aurelien Ribon
1
@ Aurélien: Si cela vous fait vous sentir mieux, de nombreuses classes du .NET Framework sont scellées, à la grande consternation de certains utilisateurs qui souhaitent étendre les classes du framework avec leurs propres fonctionnalités. Cependant, cette limitation peut être quelque peu atténuée en utilisant des méthodes d'extension.
Robert Harvey,
1
Je pense qu'il s'agit plus d'immuabilité que d'éviter l'extension. En d'autres termes, l'utilisation de finalchamps et non de méthodes. Les classes immuables peuvent également être conçues pour être étendues.
Jonas
15

Le problème avec l'utilisation finalpour transmettre que quelque chose est en lecture seule est qu'il ne fonctionne vraiment que pour les types primitifs comme int, charetc. Par conséquent, lorsque vous utilisez le finalmot clé sur un objet, vous dites seulement que la référence est en lecture seule, l'objet lui-même est toujours modifiable.

Il aurait pu être utilisé davantage s'il avait effectivement rendu l'objet en lecture seule. En C ++, c'est exactement ce qui constfait et, par conséquent, c'est un mot-clé beaucoup plus utile et très utilisé.

Un endroit que j'utilise le finalmot - clé est fortement avec les paramètres pour éviter toute confusion créée par des choses comme ceci:

public void someMethod(FancyObject myObject) {
    myObject = new FancyObject();
    myObject.setProperty(7);
}
...
public static void main(final String[] args) {
    ...
    FancyObject myObject = new FancyObject();
    someOtherObject.someMethod(myObject);
    myObject.getProperty(); // Not 7!
}

Dans cet exemple, il semble évident pourquoi cela ne fonctionne pas, mais si someMethod(FancyObject)c'est une confusion grande et compliquée peut en résulter. Pourquoi ne pas l'éviter?

Cela fait également partie des normes de codage Sun (ou Oracle maintenant, je suppose).

Gyan aka Gary Buyn
la source
1
S'il y avait eu plus d'utilisation finaldans les classes d'API Java, la plupart des objets étaient immuables comme avec de nombreuses bibliothèques Scala. La création de champs d'objet finalrend la classe immuable dans de nombreux cas. Cette conception est déjà utilisée dans BigDecimalet String.
Jonas
@Jonas J'ai lu la question pour en savoir plus sur le point 4 de la réponse de schmmd car il disait "car les gens peuvent facilement voir ce qui sont des variables en lecture seule" et j'ai répondu en conséquence. J'aurais peut-être dû inclure cette hypothèse dans la réponse.
Gyan aka Gary Buyn
Gardez à l'esprit qu'il existe un moment où vous souhaitez réaffecter le paramètre. Par exemple, le découpage d'un paramètre de chaîne.
Steve Kuo
@Steve Je crée généralement une nouvelle variable à affecter dans cette situation.
Gyan aka Gary Buyn
1
@Gary, pour moi au moins, il est très rare que des bugs / confusion soient causés par la réaffectation d'un paramètre. Je préfère de loin avoir du code sans encombrement et accepter la possibilité à distance de réaffecter un paramètre provoquant un bogue. Soyez juste prudent lorsque vous écrivez / modifiez du code.
Steve Kuo
4

J'accepte que le finalmot - clé améliore la lisibilité. Cela rend beaucoup plus facile à comprendre quand un objet est immuable. Cependant, en Java, il est extrêmement verbeux, en particulier (à mon avis) lorsqu'il est utilisé sur des paramètres. Cela ne veut pas dire que les gens ne devraient pas l'utiliser parce qu'il est verbeux, mais plutôt qu'ils ne l'utilisent pas parce qu'il est verbeux.

Une autre langue, comme scala, facilite beaucoup les déclarations finales ( val ). Dans ces langues, les déclarations finales peuvent être plus courantes que les variables.

Notez qu'il existe de nombreuses utilisations différentes du mot clé final. Votre message couvre principalement les articles 2 et 3.

  1. Classes finales (JLS 8.1.1.2)
  2. Champs finaux (JLS 8.3.1.2)
  3. Méthodes finales (JLS 8.4.3.3)
  4. Variables finales (JLS 4.12.4)
schmmd
la source
2

Pour commencer, les conventions officielles du code Java ne favorisent ni n'interdisent une utilisation particulière de final. Autrement dit, les développeurs JDK sont libres de choisir la façon dont ils préfèrent.

Je ne peux pas lire dans leurs pensées, mais pour moi, la préférence à utiliser finalou non a été une question de concentration. Une question de savoir si j'ai assez de temps pour me concentrer complètement sur le code ou non .

  • Disons que dans un de mes projets, nous pourrions nous permettre de dépenser en moyenne une journée sur 100 lignes de code. Dans ce projet, j'avais une perception distincte finalcomme une poubelle qui obscurcit simplement des choses qui sont déjà exprimées suffisamment clairement dans le code. Il semble que les développeurs JDK entrent également dans cette catégorie.
     
    En revanche, c'était totalement opposé dans un autre projet, où nous avons passé une heure en moyenne sur 100 lignes de code. Là, je me suis retrouvé à tirer finalcomme une mitraillette dans mon propre code et dans celui des autres - simplement parce que c'était le moyen le plus rapide de détecter une intention du gars qui l'a écrit avant moi et, de même, le moyen le plus rapide de communiquer mon intention de le gars qui travaillera sur mon code plus tard.

Cela peut également donner un petit coup de pouce au JIT, et bien que ce soit très limité, cela ne peut pas nuire

Le raisonnement comme ci-dessus est glissant. L'optimisation prématurée peut nuire; Donald Knuth va jusqu'à l'appeler "la racine de tout mal" . Ne vous laissez pas piéger. Écrivez un code stupide .

moucheron
la source
2

Récemment, j'ai découvert la joie de la fonction "Enregistrer les actions" dans Eclipse IDE. Je peux le forcer à reformater mon code, insérer des @Overrideannotations manquantes et faire des trucs astucieux comme supprimer les parenthèses inutiles dans les expressions ou mettre des finalmots clés partout automatiquement à chaque fois que je frappe ctrl + S. J'ai activé certains de ces déclencheurs et, mon garçon, ça aide beaucoup!

Il s'est avéré que bon nombre de ces déclencheurs agissent comme une vérification rapide de la validité de mon code.

  • J'avais l'intention de remplacer une méthode mais l'annotation ne s'affichait pas lorsque je frappais ctrl + s? - peut-être que j'ai foiré les types de paramètres quelque part!
  • Certaines parenthèses ont été supprimées du code lors de l'enregistrement? - peut-être que cette expression logique est beaucoup trop difficile pour un programmeur de se déplacer rapidement. Sinon, pourquoi ajouter ces parenthèses en premier lieu?
  • Ce paramètre ou variable locale ne l'est pas final. Est - ce qu'il a de changer sa valeur?

Il s'est avéré que moins de variables changent, moins j'ai de problèmes au moment du débogage. Combien de fois vous suiviez la valeur d'une variable pour constater qu'elle change en quelque sorte de 5 à 7 par exemple? "Comment diable ça pourrait être?!" vous vous demandez et passez les prochaines heures à entrer et sortir d'innombrables méthodes pour découvrir que vous avez fait une erreur dans votre logique. Et pour y remédier, vous devez ajouter un indicateur supplémentaire, quelques conditions et modifier soigneusement certaines valeurs ici et là.

Oh, je déteste le débogage! Chaque fois que je lance le débogueur, j'ai l'impression que mon temps est compté et j'ai désespérément besoin de ce temps pour réaliser au moins certains de mes rêves d'enfance! Au diable le débogage! finals ne signifie plus de changements de valeur mystérieux. Plus de finals => parties moins fragiles dans mon code => moins de bugs => plus de temps pour faire de bonnes choses!

En ce qui concerne les finalcours et les méthodes, je m'en fiche vraiment. J'adore le polymorphisme. Le polymorphisme signifie que la réutilisation signifie moins de code signifie moins de bogues. La machine virtuelle Java fait un très bon travail avec la dévirtualisation et l'inclusion de méthode de toute façon, donc je ne vois pas de valeur à tuer les possibilités de réutilisation de code pour des avantages de performances non fiables.


Voir tous ces finals dans le code est quelque peu distrayant au début et prend aussi du temps pour s'y habituer. Certains de mes coéquipiers sont toujours très surpris de voir autant de finalmots clés. Je souhaite qu'il y ait un paramètre dans l'EDI pour une coloration syntaxique spéciale. Je serais heureux de le passer à une certaine nuance de gris (comme des annotations) afin qu'ils ne soient pas trop distrayants lors de la lecture du code. Eclipse a actuellement une couleur distincte pour returntous les autres mots clés, mais pas pour final.

Andrew Андрей Листочкин
la source
1
Vous pourriez peut-être envisager de rechercher des langages fonctionnels comme OCaml ou F #. Ces langages ont tendance à nécessiter beaucoup moins de débogage, l'une des raisons étant que tout est en lecture seule par défaut. Autrement dit, une fois affectée, une variable dans un langage fonctionnel ne change pas.
Abel
1
Oui, je le sais et j'écris du code ML de temps en temps - c'est de là que je tire mon inspiration :) Il ne s'agit pas du langage que vous utilisez mais plutôt des principes et des techniques que vous appliquez. On peut tout faire impérativement avec Haskell et la donotation :) Bien sûr, Java n'est pas le meilleur langage pour écrire dans un style fonctionnel mais au moins il vous permet d'écrire du code robuste - et c'est ce qui m'importe vraiment.
Andrew Андрей Листочкин