제이온

[Effective Java] Item 6 : Évitez la création d'objets inutiles

Création: 2024-04-28

Création: 2024-04-28 13:40

Cas de création d'objets inutiles

Utilisation de new String()


Les chaînes de caractères a, b et c contiennent toutes la chaîne de caractères « hi ». Cependant, comme l'adresse à laquelle ces trois chaînes de caractères font référence est différente, elles allouent des mémoires distinctes pour les mêmes données, ce qui entraîne un gaspillage.


<span class="image-inline ck-widget" contenteditable="false"><img src="https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2Fa53d14aa-6abf-40f0-8441-435647d172fa%2FUntitled.png?table=block&id=f168859c-367c-4924-a4c6-5e04788fab67&spaceId=b453bd85-cb15-44b5-bf2e-580aeda8074e&width=2000&userId=80352c12-65a4-4562-9a36-2179ed0dfffb&cache=v2" alt="Untitled" style="aspect-ratio:2000/1146;" width="2000" height="1146"></span>


Par conséquent, lors de la déclaration d'une chaîne de caractères, il est préférable d'utiliser une littérale au lieu du mot-clé new.



Le code source ci-dessus n'utilise qu'une seule instance. De plus, en utilisant cette méthode, on garantit que tous les codes utilisant la littérale de chaîne de caractères « hi » dans la même JVM réutilisent le même objet. Cela est dû aux caractéristiques du pool de constantes Java.


Utilisation de new Boolean()

Le code ci-dessus crée une instance Boolean via un constructeur prenant une chaîne de caractères en paramètre. Boolean ne peut prendre que les valeurs true ou false, et créer une instance à chaque fois est un gaspillage de mémoire. Il est donc préférable d'utiliser la méthode d'usine statique Boolean.valueOf().



Utilisation de String.matches()

Il est conseillé de mettre en cache et de réutiliser les objets dont le coût de création est élevé, mais on ne connaît pas toujours le coût des objets que l'on crée. Par exemple, si l'on souhaite écrire une méthode qui vérifie si une chaîne de caractères donnée est un nombre romain valide, il est plus facile d'utiliser une expression régulière comme suit :



Cependant, la méthode String.matches() pose des problèmes de performances. L'instance Pattern destinée aux expressions régulières créée en interne par cette méthode est utilisée une seule fois puis supprimée, devenant rapidement une cible pour le ramassage des ordures. Plus la fréquence d'utilisation de l'expression régulière est élevée, plus le coût de création et de suppression des instances Pattern identiques augmente. Il est donc préférable de mettre en cache l'instance Pattern à l'avance et de la réutiliser chaque fois que la méthode isRomanNumeral() est appelée.



**Points importants**

Dans tous les exemples ci-dessus, les objets inutiles mis en cache ont été rendus immuables. C'est pour que leur réutilisation soit sécurisée. Cependant, il existe des cas où la réutilisation d'objets immuables va à l'encontre de l'intuition.


Un adaptateur (vue) est un objet qui délègue les tâches réelles à un objet back-end et joue le rôle d'une deuxième interface. Comme l'adaptateur n'a besoin de gérer que l'objet back-end, il suffit de créer un adaptateur par objet back-end.


Par exemple, la méthode keySet() de l'interface Map renvoie une vue Set contenant toutes les clés de l'objet Map. L'utilisateur peut penser qu'une nouvelle instance Set est créée à chaque appel de la méthode keySet(), mais en réalité, l'implémentation JDK renvoie toujours la même instance Set mutable.


Cela est dû au fait que les fonctions exécutées par toutes les instances Set sont identiques, même si l'instance Set renvoyée est mutable, et que toutes les instances Set représentent l'instance Map. Par conséquent, il n'y a pas de problème à ce que keySet() crée plusieurs objets vue, mais cela n'est pas nécessaire et ne présente aucun avantage.



Par conséquent, si l'instance names1 est modifiée comme ci-dessus, l'instance names2 est également affectée.


Cependant, je pense personnellement que la valeur de retour de la méthode keySet() doit utiliser une copie défensive pour renvoyer une nouvelle instance à chaque fois. Si l'instance Set reçue par la méthode keySet() est également utilisée ailleurs et qu'il existe du code qui modifie l'état de cette instance, on ne peut plus être sûr de l'état actuel de l'instance Set et de l'instance Map.


De plus, à moins que l'environnement n'utilise pas excessivement keySet(), la création répétée de l'interface Set n'a pas d'impact significatif sur les performances. Je pense qu'il est préférable de rendre l'interface Set immuable pour une maintenance plus sûre.


Autoboxing

L'autoboxing est une technique qui convertit automatiquement les types primitifs et les types enveloppants lorsque les programmeurs les utilisent de manière interchangeable. Cependant, l'autoboxing ne supprime pas complètement la distinction entre les types primitifs et les types enveloppants, mais la brouille.



Il n'y a pas de problème logique, mais le code est très inefficace en termes de performances. La cause en est le type de sum et le type de i dans la boucle for.


Le type de sum est Long et celui de i est long. En d'autres termes, lorsque le type long de i est ajouté à sum lors de l'exécution de la boucle, une nouvelle instance Long est créée à chaque fois. En conclusion, il est préférable d'utiliser des types primitifs plutôt que des types enveloppants et de faire attention à éviter l'autoboxing involontaire.


Points à ne pas mal interpréter

Il ne faut pas mal interpréter l'idée d'éviter la création d'objets inutiles en pensant simplement qu'il faut les éviter car leur coût de création est élevé.


En particulier, dans les JVM modernes, la création et la suppression d'objets de petite taille inutiles ne sont pas une tâche très lourde. Par conséquent, à moins qu'il ne s'agisse d'objets dont le coût est très élevé, comme une connexion à une base de données, il ne faut pas créer de pool d'objets personnalisé.


De plus, n'oubliez pas que les dommages causés par la réutilisation d'objets dans des situations où une copie défensive est nécessaire sont bien plus importants que les dommages causés par la création répétée d'objets inutiles. Les effets secondaires de la création répétée n'affectent que la forme du code et les performances, mais l'échec d'une copie défensive conduit directement à des bogues et à des problèmes de sécurité.


Sources

Commentaires0

[Hors informatique, survivre en tant que développeur] 14. Résumé des questions techniques fréquemment posées lors d'un entretien d'embauche pour développeur débutantNous avons résumé et organisé les questions techniques fréquemment posées lors des entretiens d'embauche pour les développeurs débutants (zones de mémoire, structures de données, bases de données, etc.). Nous espérons que cela vous aidera dans votre prépa
투잡뛰는 개발 노동자
투잡뛰는 개발 노동자
투잡뛰는 개발 노동자
투잡뛰는 개발 노동자

April 3, 2024