Java Strings
Introduction
Les strings (chaînes de caractères, c'est-à-dire des suites de lettres, de chiffres et de symboles) servent à représenter un texte quelconque. Aux débuts de l'informatique, les langages de programmation étaient limités et ne proposaient pas de support multilingue. Dans le monde globalisé d'aujourd'hui, les strings peuvent contenir n'importe quel type de caractère.

Avec Java et la prise en charge d'Unicode (norme universelle qui attribue un numéro unique à chaque caractère de toutes les langues), les strings sont devenues plus puissantes mais aussi plus complexes. Dans cette quête, on va lever quelques-uns des secrets des strings en Java.
🤓 À la fin de cette quête, tu vas :
✅ Connaître quelques détails intéressants sur les strings et la façon dont Java les gère ✅ Comprendre certains aspects du support multilingue en programmation
Utiliser des strings en Java est vraiment simple. Tout ce que tu as à faire, c'est déclarer une variable de type string et, éventuellement, lui assigner une valeur.
String helloStrings = "Hello Strings";
Quand tu regardes les caractères de la valeur assignée et que tu te souviens que chaque caractère a besoin de 2 octets (16 bits) de stockage, tu vois que cette petite string occupe plus de place que n'importe quelle valeur de type long. Une variable de type long fait toujours 8 octets, et c'est aussi le nombre maximum d'octets nécessaire pour n'importe quel type numérique. Cette string a 13 caractères et a besoin de 26 octets de mémoire.
Tu peux assigner à une variable string une valeur de n'importe quelle longueur. Il existe une limite autour de 2 Go qui permettrait à une seule string de contenir le texte de la Bible. En pratique, on peut considérer sans grand risque que les strings sont illimitées, sauf si tu dois gérer un texte vraiment très très grand.
Tu peux toujours assigner une nouvelle valeur à une variable string. Il y a cependant une grande différence quand tu compares les variables string avec les variables numériques.
int i = 1000;
i = 1000000;
String s = "Hello";
s = "Hello world";
Avec une variable de type int, n'importe quelle valeur entière tiendra toujours dans la variable, car elle n'aura jamais besoin de plus que les 4 octets de stockage toujours utilisés pour les variables de type int.
Avec une string, tu devrais réserver 2 Go de mémoire pour chaque string, juste au cas où une string aussi grande serait assignée à cette variable. Mais ça ne se passe pas comme ça. Au lieu de réserver toute la mémoire d'un coup, une string n'a besoin que de quelques octets, et la mémoire nécessaire à la valeur assignée est allouée dynamiquement au moment où la valeur est assignée à la string.
String s; // requires only a few bytes of memory
s = "Hello world"; // will allocate more mory for the value "Hello world"
La variable s et la valeur string "Hello world" sont en réalité deux choses complètement différentes en mémoire, simplement reliées entre elles. C'est différent des variables de types primitifs (les types de base comme int ou boolean), où la variable et la valeur se trouvent au même endroit en mémoire.
Tu peux faire explicitement une allocation dynamique de mémoire pour la valeur string avec le mot-clé new, comme dans l'exemple suivant :
String s; // requires only a few bytes of memory
s = new String("Hello world"); // explicit dynamic memory allocation
Mais ne fais surtout pas ça toi-même, car le langage Java le fera pour toi. Si tu utilisais new toi-même, ça pourrait arriver deux fois et consommer deux fois plus de mémoire que nécessaire. Pas vraiment, en fait, parce que le compilateur Java sera assez malin pour se rendre compte que la mémoire n'est pas nécessaire deux fois.
String s;
s = new String( new String( "Hello world" )); // what could happen if the Java was not smart
Un autre détail important des strings, c'est le fait qu'elles ne sont jamais modifiées. Au lieu de modifier une string, Java crée simplement une nouvelle string avec le nouveau contenu.
String s;
s = "Hello";
s = s + "world"; // the string "Hello" is not changed, s references a new string "Hello world"
Allouer de la mémoire pour les strings peut prendre du temps et provoquer des problèmes de performance dans une application.
Les strings qu'on utilise dans notre programme ne sont pas modifiées, elles servent à construire de nouvelles strings. Ça peut avoir des effets de bord. Si on additionne des strings avec l'opérateur +, une nouvelle string est créée.
String s;
s = "Hello"; // s1 is never modified
s = s + " world";
Dans cet exemple, on a créé les strings "Hello", " world" et "Hello world".
Regarde le bout de code Java suivant. Dans ce cas, chaque caractère de la string " world" est ajouté un par un. Remarque qu'à chaque fois qu'on ajoute un seul caractère, une nouvelle string est allouée en mémoire avec juste ce caractère supplémentaire.
String s;
s = "Hello";
s = s + " ";
s = s + "w";
s = s + "o";
s = s + "r";
s = s + "l";
s = s + "d";
Dans cet exemple, on a créé les strings "Hello", " world", "Hello ", "Hello w", "Hello wo", "Hello wor", "Hello worl", et "Hello world". Au lieu de trois strings, on a maintenant créé huit strings en mémoire.
Essaie d'éviter d'ajouter des caractères seuls ou de petits morceaux de caractères aux strings.
Pour éviter l'allocation excessive de mémoire quand on additionne des strings, Java fournit la classe StringBuilder. Java fournit aussi la classe StringBuffer, avec des fonctionnalités similaires. StringBuffer est plus ancienne, et tu peux voir StringBuilder comme une classe qui remplace StringBuffer.
StringBuffer alloue un peu d'espace qui est consommé au fur et à mesure que tu ajoutes des caractères. Tu ne peux pas utiliser l'opérateur + avec StringBuffer pour ajouter des caractères. Utilise la méthode append (ajouter à la fin) à la place.
String s;
StringBuilder sb = new StringBuilder("Hello"); // similar to new String("Hello");
sb.append(" ");
sb.append("w");
sb.append("o");
sb.append("r");
sb.append("l");
sb.append("d");
s = sb.toString();
Cette solution est bien plus efficace en mémoire que la simple concaténation (mise bout à bout) de strings.
Même si StringBuffer alloue un peu d'espace pour des caractères supplémentaires, tu peux avoir besoin de plus de place. Dans ce cas, StringBuffer va allouer de la nouvelle mémoire et recopier tous les octets, ce qui peut être lent. Ça peut aussi arriver plus d'une fois à mesure que tu ajoutes des caractères.
Les strings Java peuvent être délicates et ralentir l'exécution du programme quand tu ne comprends pas comment Java gère les strings.
Les strings Java et Unicode
Les strings en Java ont besoin de 2 octets, soit 16 bits, de stockage et sont encodées selon la norme UTF-16. Pour mieux comprendre Unicode, tu dois connaître les notions de code point et de code unit, et savoir qu'Unicode peut être l'un des encodages UTF-8, UTF-16 ou UTF-32.
Code point
Un code point (point de code : la valeur entière unique qui identifie un caractère) est une valeur entière unique qui identifie un caractère. Avec UTF-16, il y a 65536 code points, chaque nombre représentant un caractère précis. Les caractères font 16 bits de large.
Code unit
Un code unit (unité de code : la séquence d'octets utilisée pour encoder un caractère) est une séquence d'octets utilisée pour encoder un caractère. Les séquences n'ont pas de longueur fixe et un caractère est représenté par une séquence d'au moins 1 octet.
Certains caractères en Unicode utilisent un seul code point, mais parfois un seul caractère a besoin d'un code unit plus long qu'une seule valeur de 8, 16 ou 32 bits. Pour examiner ça un peu, on crée une méthode qui inverse le contenu d'une string.
String reverse(String original) {
String reversed = "";
for (int i = original.length() - 1; 0 <= i; i--) {
reversed += original.charAt(i);
}
return reversed;
}
Exécute-la avec les strings suivantes :
String first = "ABC"; // ASCII compatible letters A, B and C
String second = "𝔸BC"; // A variant of the letter A
Avec la deuxième string, le premier caractère n'est pas la lettre A de l'alphabet, et il y a une grosse différence dans la quantité de mémoire nécessaire pour stocker cette string. Tu peux vérifier la longueur des deux strings pour voir la différence.
first.length();
second.length();
Une autre option consiste à utiliser la séquence d'échappement Unicode (une notation spéciale pour écrire un caractère qu'on ne peut pas taper directement) pour spécifier la string de façon explicite.
String first = " ABC"; // ASCII compatible letters A, B and C
String second = "𝔸BC"; // A variant of the letter A
Comme les emojis font désormais partie des jeux de caractères Unicode, tu n'as même pas besoin d'utiliser une langue étrangère (y compris les mathématiques) pour tomber sur des problèmes de caractères. Écrire du code qui gère correctement les strings dans tous les cas est devenu plus difficile dans un monde globalisé.
Référence
La documentation Java contient encore plus de détails sur le fonctionnement des strings en Java.
Pour finir, voici une façon qui marche et qui inverse une string :
new StringBuilder(second).reverse().toString()
La plupart du temps, Java a déjà une solution à un problème, surtout pour les choses de base comme inverser une string. Ça vaut toujours le coup d'investir un peu de temps pour trouver une solution existante qui marche, plutôt que d'écrire ta propre solution bancale.
☝️ Résumé
Avec les caractères ASCII, la gestion des strings est simple et directe une fois que tu as bien compris les bases. Avec Unicode, les choses sont devenues plus difficiles, mais une fois que tu es conscient du problème, tu peux faire marcher ton code même dans un contexte international.
💪 Défi
Tu ne peux pas utiliser certains caractères directement dans un littéral string en Java. Pour ajouter ces caractères spéciaux dans une string, tu dois utiliser une séquence d'échappement, mais tu peux aussi utiliser la séquence d'échappement Unicode. Cherche l'Unicode de chacun des huit caractères spéciaux que tu écris habituellement avec la séquence d'échappement. Affiche le caractère et la longueur de la string contenant ce caractère.
La classe String fournit des méthodes pour convertir une string tout en majuscules ou tout en minuscules. Que se passe-t-il avec les caractères spéciaux, par exemple l'Umlaut allemand ("ä"), les accents populaires en France ("é") ou la lettre danoise "Ø" ?
Essaie les méthodes valueOf sur tous les types primitifs et compare la longueur de la sortie, le nombre d'octets de la sortie et le nombre d'octets du type primitif.
Écris une méthode qui découpe une string contenant une phrase en mots et inverse l'ordre des mots.
Écris une méthode qui découpe une string contenant une phrase en mots et inverse l'ordre des caractères dans chaque mot, tout en conservant l'ordre des mots dans la phrase.
🧐 Critères d'acceptation
- ✔ Tu as terminé le défi
- ✔ Un autre étudiant a relu ton travail
- ✔ Ton code est disponible dans ton dépôt git (Github, Gitlab, ...)
Introduction
Strings are used to present an arbitrary text. In the early days of computing, programming languages where limited and did not include multi-language support. In todays global world, strings can contain any kind of character.

With Java and the support for Unicode, strings became more powerful but also more complex. In this quest, we will lift some of the secrets of Java strings.
🤓 By the end of this quest, you will:
✅ Know some interesting details about strings and Java's handling of strings ✅ Understand some aspects of multi-language support in programming
Using strings in Java is really simple. All you have to do is declare a variable of data type string and optionally assign a string value to that variable.
String helloStrings = "Hello Strings";
When you look at the characters from the assigned string value and you remember that each character requires 2 bytes (16 bit) of storage, you will see that this short strings requires more space than any long value. A variable of data type long is always 8 bytes and that is also the maximum number of bytes required for any numeric data type. This string has 13 characters and requires 26 bytes of memory.
You can assign a string value of any length to a string variable. There is a limit at around 2GB that will allow a single string to contain the text of the bible. In practice, it is rather safe to assume that strings are unlimited unless you have to handle a really really large text.
You can always assign a new value to a string variable. There is a big difference though when you compare string variables with numeric variables.
int i = 1000;
i = 1000000;
String s = "Hello";
s = "Hello world";
With a variable of type int, any integer value will always fit into the variable as it will never require more than the 4 bytes of storage that are always used for variables of type int.
With a string, you would have to reserve 2GB of memory for every string just in case such a large string would be assigned to this variable. But this does not happen. Instead of reserving all memory at once, a string will only require a few bytes and the memory required for any assigned string value is dynamically allocated whenever the value is assigned to the string.
String s; // requires only a few bytes of memory
s = "Hello world"; // will allocate more mory for the value "Hello world"
The variable s and the string value "Hello world" are really two completly different things in memory that are just related. This is different from variables of primitive data types where variable and value are located in the same place in memory.
You can explicitly make a dynamic allocation of memory for the string value with the new keyword as in the following example:
String s; // requires only a few bytes of memory
s = new String("Hello world"); // explicit dynamic memory allocation
Just do not do this yourself as the Java language will do it for you. If you would use new yourself, it could happen twice and consume twice as much memory as required - not really, but that is just because the Java compiler will be smart enough to realize that the memory is not needed twice.
String s;
s = new String( new String( "Hello world" )); // what could happen if the Java was not smart
Another important detail of strings is the fact, that strings are never changed. Instead of changing a string, Java will simply create a new string with the new content.
String s;
s = "Hello";
s = s + "world"; // the string "Hello" is not changed, s references a new string "Hello world"
Allocating memory for strings can be time consuming and lead to performance issues with an application.
The strings we use in our program are not modified, they are used to build new strings. This can have side effects. If we add strings with the + operator, a new string is created.
String s;
s = "Hello"; // s1 is never modified
s = s + " world";
In this example, we have created the strings "Hello", " world" and "Hello world".
Look at the following Java code snippet. In this case, each character of the string " world" is added one by one. Notice that each time we add a single character, a new string is allocated in memory with just this additonal character.
String s;
s = "Hello";
s = s + " ";
s = s + "w";
s = s + "o";
s = s + "r";
s = s + "l";
s = s + "d";
In this example, we have created the strings "Hello", " world", "Hello ", "Hello w", "Hello wo", "Hello wor", "Hello worl", and "Hello world". Instead of three strings, we now have created eight strings in memory.
Try to avoid adding single characters or small chunks of characters of strings
To avoid the excessive memory allocation when adding strings, Java provides the StringBuilder class. Java also provides the StringBuffer class with similar features. The StringBuffer is older and you can think of StringBuilder as a class that supersedes StringBuffer.
StringBuffer allocates some space that is used up as you append characters. You can not use the + operator with StingBuffer to append characters. Use the append method instead.
String s;
StringBuilder sb = new StringBuilder("Hello"); // similar to new String("Hello");
sb.append(" ");
sb.append("w");
sb.append("o");
sb.append("r");
sb.append("l");
sb.append("d");
s = sb.toString();
This solution is much more memory efficient than simple string concatenation.
Even though the StringBuffer allocates some space for additional characters, you may require more space. In that case, StringBuffer will allocate some new memory and copy all the bytes over which can be slow. It could also happen more than once as you add more characters.
Java strings can be tricky and slow programm execution when you do not understand how Java handles strings.
Java strings and Unicode
Strings in Java require 2 bytes or 16 bits of storage and are encoded in the UTF-16 standard. To understand Unicode better you have to know about code points and code units and that Unicode can be any of UTF-8, UTF-16 or UTF-32.
Code point
A code point is a unique integer value that identifies a character. With UTF-16, there are 65536 code points with each number representing a specific character. Characters are 16 bytes wide.
Code unit
A code unit is a byte sequence used to encode a character. Sequences have no fixed length and a character is represented by a sequence of at least 1 byte or
Some characters in Unicode use a single code point but sometimes a single character requires a code unit that is longer than a single 8, 16 or 32 bit value. To examine this a bit, we create a method to reverse the content of a string.
String reverse(String original) {
String reversed = "";
for (int i = original.length() - 1; 0 <= i; i--) {
reversed += original.charAt(i);
}
return reversed;
}
Run this with the following strings:
String first = "ABC"; // ASCII compatible letters A, B and C
String second = "𝔸BC"; // A variant of the letter A
With the second string, the first character is not the letter A from the Alphabet and there is a major difference in the amount of memory that is required to store this string. You can verify the length of both strings to see the difference.
first.length();
second.length();
Another option is to use the Unicode escape character sequence to specify the string explicitly
String first = " \u0041\u0042\u0043"; // ASCII compatible letters A, B and C
String second = "\uD835\uDD38\u0042\u0043"; // A variant of the letter A
As Emoji's are now part of the Unicode character sets, you do not even have to use a foreign language (including maths) to run into problems with characters. Writing code to handle strings correctly in all cases has become more difficult in a global world.
Reference
The Java documentation includes even more details about how strings work in Java.
Finally, here is a way that works and reverses a string
new StringBuilder(second).reverse().toString()
Most of the time, Java will already have a solution for a problem, especially for basic things like reverse a string. It is always worth to invest some time to find an existing solution that works instead of writing your own soultion that is broken.
☝️ Summary
With ASCII characters, string handling is simple and straight forward once you get the basics right. With Unicode, things became more difficult but once you are aware of the problem, you can make your code work even in an international environment.
💪Challenge
You can not use some characters within a string literal in Java directly. To add these special characters in a string, you have to use an escape character sequence but you can also use the unicode escape sequence. Look up the unicode for all of the eight special characters that you usually write down with the escape sequence. Print the character and the length of the string with that character.
The String class provides methods to convert a string to all uppercase or all lowercase. What happens with special characters, e.g. the german Umlaut ("ä"), the accents popular in france ("é") or the danish letter "Ø".
Try out the valueOf methods on all primitive data types and compare the length of the output, the number of bytes of the output and the number of bytes for the primitive data type.
Write a method that splits a string with a sentence into words and reverses the order of the words.
Write a method that splits a string with a sentence into words and reverses the order of the characters in each word while maintaining the order of the words in the sentence.
🧐 Acceptance criteria
- ✔ You completed the challenge
- ✔ Another student reviewd your work
- ✔ Your code is available in your git repository (Github, Gitlab, ...)