D'après mon expérience, il n'y a qu'une et une seule raison de ne pas le faire Object.finalize()
, mais c'est une très bonne raison :
Pour placer le code de consignation d’erreur finalize()
qui vous avertit si vous oubliez d’invoquer close()
.
L'analyse statique ne peut détecter que les omissions dans les scénarios d'utilisation triviaux, et les avertissements du compilateur mentionnés dans une autre réponse ont une vue tellement simpliste de la nécessité de les désactiver pour pouvoir effectuer quelque chose de non trivial. (J'ai beaucoup plus d'avertissements activés que n'importe quel autre programmeur que je connaisse ou dont j'ai entendu parler, mais je n'ai pas activé les avertissements stupides.)
La finalisation peut sembler être un bon moyen de s’assurer que les ressources ne restent pas inaperçues, mais la plupart des gens le voient d’une manière totalement fausse: ils le voient comme un mécanisme de secours alternatif, une sauvegarde "de la seconde chance" qui sauvera automatiquement le jour en disposant des ressources qu’ils ont oubliées. C'est complètement faux . Il doit exister une seule façon de faire une chose: soit on ferme toujours tout, soit la finalisation ferme toujours tout. Mais comme la finalisation n'est pas fiable, elle ne peut l'être.
Donc, il y a ce schéma que j'appelle élimination obligatoire , et il stipule que le programmeur est responsable de toujours fermer explicitement tout ce qui implémente Closeable
ou AutoCloseable
. (L'instruction try-with-resources compte toujours en tant que clôture explicite.) Bien sûr, le programmeur peut oublier. C'est là que la finalisation entre en jeu, mais pas en tant que fée magique qui remettra les choses à la magie à la fin: si la finalisation découvre qui close()
n'a pas été invoqué, cela ne signifie pasessayez de l'invoquer, précisément parce qu'il y aura (avec une certitude mathématique) des hordes de programmeurs n00b qui compteront dessus pour faire le travail pour lequel ils étaient trop paresseux ou trop distants. Donc, avec l'élimination obligatoire, lorsque la finalisation découvre que cela close()
n'a pas été invoqué, un message d'erreur rouge vif est consigné, indiquant au programmeur, avec de grosses lettres majuscules, de réparer ses affaires.
Un avantage supplémentaire, selon la rumeur , "la machine virtuelle Java ignorera une méthode trivial finalize () (par exemple, une méthode qui retourne sans rien faire, comme celle définie dans la classe Object)", ce qui permet d' éviter toute suppression à la finalisation. des frais généraux dans tout votre système ( voir la réponse d' Alip pour des informations sur la gravité de ces frais) en codant votre finalize()
méthode comme suit :
@Override
protected void finalize() throws Throwable
{
if( Global.DEBUG && !closed )
{
Log.Error( "FORGOT TO CLOSE THIS!" );
}
//super.finalize(); see alip's comment on why this should not be invoked.
}
L’idée sous-jacente est qu’il s’agisse d’ Global.DEBUG
une static final
variable dont la valeur est connue au moment de la compilation. Si c’est le cas, false
le compilateur n’émettra aucun code pour l’ if
instruction complète , ce qui en fera un finaliseur trivial (vide), qui à son tour signifie que votre classe sera traitée comme si elle n'avait pas de finaliseur. (En C #, cela se ferait avec un beau #if DEBUG
bloc, mais que pouvons-nous faire, java, où nous payons une simplicité apparente dans le code avec une surcharge supplémentaire dans le cerveau.)
Pour en savoir plus sur la disposition obligatoire, avec des discussions supplémentaires sur la disposition des ressources dans dot net, ici: michael.gr: Élimination obligatoire ou abomination "Éliminer-éliminer"
finalize()
est un peu gâchée. Si vous l'implémentez, assurez-vous qu'il est thread-safe par rapport à toutes les autres méthodes sur le même objet.