Pourquoi String est immuable en Java?

1. Introduction

En Java, les chaînes sont immuables. Une question évidente qui est assez répandue dans les entretiens est «Pourquoi les chaînes sont conçues comme immuables en Java?»

James Gosling, le créateur de Java, a été une fois demandé dans une interview quand utiliser des immuables, ce à quoi il répond:

J'utiliserais un immuable chaque fois que je le peux.

Il soutient en outre son argument en déclarant les fonctionnalités fournies par l'immuabilité, telles que la mise en cache, la sécurité, la réutilisation facile sans réplication, etc.

Dans ce didacticiel, nous explorerons plus en détail pourquoi les concepteurs de langage Java ont décidé de garder String immuable.

2. Qu'est-ce qu'un objet immuable?

Un objet immuable est un objet dont l'état interne reste constant après avoir été entièrement créé . Cela signifie qu'une fois que l'objet a été affecté à une variable, nous ne pouvons ni mettre à jour la référence ni muter l'état interne par aucun moyen.

Nous avons un article séparé qui traite en détail des objets immuables. Pour plus d'informations, lisez l'article Objets immuables en Java.

3. Pourquoi la chaîne est-elle immuable en Java?

Les principaux avantages de garder cette classe immuable sont la mise en cache, la sécurité, la synchronisation et les performances.

Discutons du fonctionnement de ces choses.

3.1. Présentation de String Pool

La chaîne est la structure de données la plus utilisée. La mise en cache des littéraux String et leur réutilisation économise beaucoup d'espace sur le tas car différentes variables String font référence au même objet dans le pool String . Le pool de stagiaires String sert exactement cet objectif.

Java String Pool est la région de mémoire spéciale dans laquelle les chaînes sont stockées par la JVM . Les chaînes étant immuables en Java, la machine virtuelle Java optimise la quantité de mémoire qui leur est allouée en ne stockant qu'une seule copie de chaque chaîne littérale dans le pool. Ce processus s'appelle le stage:

String s1 = "Hello World"; String s2 = "Hello World"; assertThat(s1 == s2).isTrue();

En raison de la présence du pool String dans l'exemple précédent, deux variables différentes pointent vers le même objet String à partir du pool, économisant ainsi une ressource mémoire cruciale.

Nous avons un article séparé dédié à Java String Pool. Pour plus d'informations, rendez-vous sur cet article.

3.2. Sécurité

La chaîne est largement utilisée dans les applications Java pour stocker des informations sensibles telles que les noms d'utilisateur, les mots de passe, les URL de connexion, les connexions réseau, etc. Elle est également largement utilisée par les chargeurs de classe JVM lors du chargement des classes.

Par conséquent, la sécurisation de la classe String est cruciale pour la sécurité de l'ensemble de l'application en général. Par exemple, considérez cet extrait de code simple:

void criticalMethod(String userName) { // perform security checks if (!isAlphaNumeric(userName)) { throw new SecurityException(); } // do some secondary tasks initializeDatabase(); // critical task connection.executeUpdate("UPDATE Customers SET Status = 'Active' " + " WHERE UserName = '" + userName + "'"); }

Dans l'extrait de code ci-dessus, disons que nous avons reçu un objet String d'une source non digne de confiance. Nous effectuons toutes les vérifications de sécurité nécessaires au départ pour vérifier si la chaîne est uniquement alphanumérique, suivie de quelques opérations supplémentaires.

N'oubliez pas que notre méthode d'appel de source non fiable fait toujours référence à cet objet userName .

Si les chaînes étaient mutables, au moment où nous exécutons la mise à jour, nous ne pouvons pas être sûrs que la chaîne que nous avons reçue, même après avoir effectué des contrôles de sécurité, serait en sécurité. La méthode de l'appelant non digne de confiance a toujours la référence et peut modifier la chaîne entre les vérifications d'intégrité. Ainsi, notre requête est sujette aux injections SQL dans ce cas. Ainsi, les chaînes mutables pourraient entraîner une dégradation de la sécurité au fil du temps.

Il peut également arriver que la chaîne userName soit visible par un autre thread, qui pourrait alors changer sa valeur après le contrôle d'intégrité.

En général, l'immuabilité vient à notre secours dans ce cas car il est plus facile d'opérer avec du code sensible lorsque les valeurs ne changent pas car il y a moins d'entrelacements d'opérations qui pourraient affecter le résultat.

3.3. Synchronisation

Le fait d'être immuable rend automatiquement le thread String sûr car ils ne seront pas modifiés lors d'un accès à partir de plusieurs threads.

Par conséquent , les objets immuables, en général, peuvent être partagés sur plusieurs threads exécutés simultanément. Ils sont également thread-safe car si un thread change la valeur, au lieu de la modifier, une nouvelle chaîne sera créée dans le pool de chaînes . Par conséquent, les chaînes sont sans danger pour le multi-threading.

3.4. Mise en cache du hashcode

Puisque les objets String sont abondamment utilisés comme structure de données, ils sont également largement utilisés dans les implémentations de hachage comme HashMap , HashTable , HashSet , etc. Lorsqu'elle fonctionne sur ces implémentations de hachage, la méthode hashCode () est appelée assez fréquemment pour le bucketing.

L'immuabilité garantit aux chaînes que leur valeur ne changera pas. Ainsi, la méthode hashCode () est remplacée dans la classe String pour faciliter la mise en cache, de sorte que le hachage est calculé et mis en cache lors du premier appel de hashCode () et que la même valeur est renvoyée depuis.

Ceci, à son tour, améliore les performances des collections qui utilisent des implémentations de hachage lorsqu'elles sont utilisées avec des objets String .

D'autre part, les chaînes mutables produiraient deux codes de hachage différents au moment de l'insertion et de la récupération si le contenu de String était modifié après l'opération, perdant potentiellement l'objet de valeur dans la carte .

3.5. Performance

Comme nous l'avons vu précédemment, le pool de chaînes existe car les chaînes sont immuables. À son tour, il améliore les performances en économisant la mémoire du tas et en accédant plus rapidement aux implémentations de hachage lorsqu'il est utilisé avec des chaînes.

Étant donné que String est la structure de données la plus utilisée, l'amélioration des performances de String a un effet considérable sur l'amélioration des performances de l'ensemble de l'application en général.

4. Conclusion

Grâce à cet article, nous pouvons conclure que les chaînes sont immuables précisément afin que leurs références puissent être traitées comme une variable normale et que l'on puisse les transmettre, entre les méthodes et entre les threads, sans se soucier de savoir si l' objet String réel sur lequel il pointe va changer.

Nous avons également appris quelles pourraient être les autres raisons qui ont incité les concepteurs de langage Java à rendre cette classe immuable.