FAQ Langage JavaConsultez toutes les FAQ
Nombre d'auteurs : 42, nombre de questions : 297, dernière mise à jour : 19 septembre 2017 Ajouter une question
Cette FAQ a été réalisée à partir des questions fréquemment posées sur le forum Java de http://java.developpez.com ainsi que l'expérience personnelle des auteurs.
Nous tenons à souligner que cette FAQ ne garantit en aucun cas que les informations qu'elle propose sont correctes. Les auteurs font leur maximum, mais l'erreur est humaine. Cette FAQ ne prétend pas non plus être complète. Si vous trouvez une erreur, ou que vous souhaitez nous aider en devenant rédacteur, lisez ceci.
Sur ce, nous vous souhaitons une bonne lecture.
- 3.5.1. Expressions régulières (3)
- Comment déclarer un caractère ?
- Les caractères sont-ils des nombres ?
- Comment représenter une chaîne de caractères en Java ?
- Comment convertir des caractères en ASCII ?
- Comment déterminer précisément le nombre de caractères d'une chaîne ?
- Comment vérifier qu'une chaîne de caractères est vide ?
- Quelle est la longueur maximale d'une chaîne de caractères ?
- Pourquoi ne pas utiliser l'opérateur + pour la concaténation de chaînes de caractères
- Comment concaténer des chaînes de caractères ?
- Comment concaténer des valeurs dans une chaîne de caractères avec un séparateur ?
- Comment comparer des chaînes de caractères ?
- Comment comparer des chaînes de caractères selon la locale ?
- Comment supprimer les accents d'une chaîne ?
- Comment gérer l'encodage d'un tableau de bytes dans des strings ?
- Comment convertir un objet quelconque en chaîne de caractères ?
- Comment découper facilement une chaîne ?
Le type char de Java est un type primitif, codé sur 16 bits, qui contient la valeur Unicode du caractère. Le type objet wrapper du type primitif char est la classe java.lang.Character.
Une valeur de type char peut se déclarer de plusieurs manières. Prenons par exemple le caractère a (lettre A minuscule) :
Code Java : | Sélectionner tout |
char a = 'a';
Ici, nous utilisons le caractère tel quel entouré de symboles ' (quote, single quote ou apostrophe).
Code Java : | Sélectionner tout |
char a = 97; // Valeur Unicode du caractère 'a'
Ici, nous utilisons un entier positif qui contient la valeur Unicode, c'est-à-dire l'index du caractère « a » dans la table des symboles Unicode UTF-16. Cette valeur doit être un entier non signé compris dans [0-65535].
Code Java : | Sélectionner tout |
char a = '\u0061'; // Valeur Unicode du caractère 'a' en hexadécimal.
Ici, nous utilisons une valeur hexadécimale qui contient ce même index (0x61 en hexadécimal vaut 97 en décimal). Cette valeur doit être un entier non signé compris dans [0x0000-0xFFFF] et elle se note toujours sur quatre chiffres après le préfixe \u. Cette dernière notation est particulièrement utile pour définir des caractères qui ne sont pas imprimables à l’écran.
Ces trois manières différentes permettent d’écrire un seul et unique caractère : le caractère a. Toutes ces méthodes sont équivalentes et donnent exactement le même résultat.
Note : pour écrire certains caractères et symboles, il vous faudra les échapper en les préfixant par le symbole antislash (ou barre contre oblique, \). Par exemple, le caractère tabulation s’écrit en fait \t, le caractère retour à la ligne s’écrit \n, tandis que le caractère retour chariot s’écrit \r. Le caractère antislash doit lui-même être échappé par un second symbole \ pour pouvoir être écrit tel quel. Il en est de même pour le caractère quote. Il nous faudra donc écrire :
Code Java : | Sélectionner tout |
1 2 3 4 5 | char tab = '\t'; char lineFeed = '\n'; char returnCariage = '\r'; char quote = '\''; // Permet d’écrire ' char aslash = '\\'; // Permet d’écrire \ |
Oui, le type char est également un nombre : char est un entier non signé qui peut contenir des valeurs de [0-65535]. Toutes les opérations et comparaisons arithmétiques sont légales sur ce type.
Attention cependant, ces opérations et comparaisons portent sur la valeur Unicode du symbole, c'est-à-dire sur son index dans la table des symboles Unicode UTF-16. De plus, les opérations arithmétiques produisent des int (entier 32 bits ou mot) et non pas des char.
Ainsi, il est tout à fait possible de faire :
Code Java : | Sélectionner tout |
1 2 3 | char a = '4'; // La valeur Unicode de '4' est 52. char b = '2'; // La valeur Unicode de '2' est 50. int c = a + b; // c vaut 102, car est égal à 52 + 50. |
Pour retrouver un char, il faudra procéder à un cast ce qui tronquera la valeur si elle dépasse la capacité du type char.
Code Java : | Sélectionner tout |
1 2 3 | char a = '4'; // La valeur Unicode de '4' est 52. char b = '2'; // La valeur Unicode de '2' est 50. char d = (char) (a + b); // d vaut 'f' car la valeur Unicode de ce symbole est 102. |
- Integral Types and Values dans les spécifications de Java.
Le moyen le plus simple de déclarer une chaîne de caractères en Java est d’écrire du texte entre " (double-quote ou guillemets). Des suites de caractères écrites dans ce format sont automatiques interprétées comme étant de type java.lang.String. Les chaînes de caractères ainsi créées sont immuables (unmutable ou encore non-mutable en anglais), c'est-à-dire qu'on ne peut plus les modifier ultérieurement. De plus, et contrairement à d'autres langages de programmation, en Java, les chaînes de caractères ne sont pas terminées par le caractère null (le caractère à l'indice 0).
Par exemple :
Code Java : | Sélectionner tout |
String maChaine = "Salut le monde !"; // Chaîne de 16 caractères.
Il est également possible d'utiliser la forme Unicode des caractères. Par exemple :
Code Java : | Sélectionner tout |
String maChaine = "S\u0061lut le monde !"; // Chaîne de 16 caractères également.
Ici, nous avons remplacé le caractère 'a' par sa notation Unicode '\u0061'. Les deux chaînes créées sont strictement identiques.
Note : comme avec la déclaration des caractères, certains symboles doivent être échappés par un antislash (ou barre contre-oblique, \) pour pouvoir être écrits. Outre ceux déjà mentionnés, le caractère double-quote (") devra également être échappé par un antislash. Il nous faudra donc écrire :
Code Java : | Sélectionner tout |
1 2 3 4 5 6 | String tab = "\t"; // La chaîne fait 1 seul caractère. String lineFeed = "\n"; // Idem. String returnCariage = "\r"; // Idem. String quote = "\'"; // Idem. Permet d’écrire ' String doubleQuote = "\""; // Idem. Permet d’écrire " String aslash = "\\"; // Idem. Permet d’écrire \ |
La manière la plus simple de passer de l'Unicode à l'ASCII est d'utiliser la classe java.lang.String.
Code Java : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | try { String chaine = "Ma chaîne à traduire !"; // Traduction en tableau de code ASCII : byte[] bytes = chaine.getBytes("ASCII"); // Affichage à l'écran : for (int i=0; i<bytes.length; i++) { System.out.println( bytes[i] ); } } catch (java.io.UnsupportedEncodingException e) { // Le codage n'est pas reconnu. e.printStackTrace(); } |
Autres formats
Quelques autres formats d'encodage sont gérés par Java en interne : US-ASCII, ISO-8859-X (avec X de 1 à 7), UTF-8, UTF-16BE, UTF-16LE, UTF-16. Veuillez vous référer à la documentation de la classe java.nio.charset.Charset pour plus d'informations.
Pour connaitre le nombre de caractères d'une chaîne, il suffit d'utiliser la méthode length() de la classe String. Cette méthode renvoie le nombre de char utilisés pour représenter la chaîne.
Cependant, en Java, un char est codé sur 2 octets alors que les caractères Unicode peuvent avoir une taille variable selon l'encodage et l’alphabet utilisés (entre 1 et 4 octets). Ainsi la valeur renvoyée par la méthode length() reflète donc plutôt la taille occupée en mémoire et non pas le nombre de caractères Unicode de la chaîne (même si dans la majorité des cas le résultat sera le même).
Ainsi, afin de connaitre avec précision le nombre de caractères réels de la chaîne, il est nécessaire d'utiliser la méthode codePointCount() de la classe String, qui permet de renvoyer le nombre de caractères Unicode entre deux emplacements de la chaîne, quelle que soit leur taille en mémoire. Ainsi, pour connaitre le nombre de caractères effectif d'un String, il faut utiliser le code suivant :
Code Java : | Sélectionner tout |
1 2 | String str = ... // la chaine int count = str.codePointCount(0, str.length()); |
L'exemple suivant permet de mettre en évidence cette différence en utilisant une lettre gothique codée sur 4 octets :
Code Java : | Sélectionner tout |
1 2 3 4 5 6 | String testString = "\uD800\uDF30"; // Un seul et unique caractère sera affiché. int charCount = testString.length(); int characterCount = testString.codePointCount(0, charCount); System.out.printf("char count: %d\n", charCount); System.out.printf("character count: %d\n", characterCount); |
Qui nous donne le résultat suivant :
Code Console : | Sélectionner tout |
1 2 | char count: 2 character count: 1 |
Pour vérifier qu'une chaîne de caractères est vide, il suffit d'invoquer sa méthode isEmpty() ou de tester si la taille retournée par la méthode length() est égale à 0.
Code Java : | Sélectionner tout |
boolean empty = maChaine.isEmpty();
ou :
Code Java : | Sélectionner tout |
boolean empty = maChaine.length() == 0;
Cependant, en général, on a plutôt tendance à vouloir vérifier que la chaîne n'est pas à la valeur null ou ne contient pas d'espaces inutiles. On aura donc plutôt tendance à effectuer le test suivant :
Code Java : | Sélectionner tout |
boolean empty = (maChaine == null) || maChaine.trim().isEmpty();
Les chaînes de caractères utilisent en interne un tableau de stockage de caractères (char[]). On notera également que les caractères de la chaîne sont indexés par des int.
En théorie, cela implique donc que la chaîne contient au maximum 231-1 éléments, soit la valeur Integer.MAX_VALUE, le plus grand entier positif possible. La plus grande plage d'indices possible pour une chaîne est donc [0, 231-2]. Cependant, il s'agit d'une limite théorique.
En pratique, dans les JVM récentes, il semble qu'il ne soit pas possible d'allouer un tableau dont la taille dépasse Integer.MAX_VALUE - 2. De plus chaque char fait 2 octets en mémoire, donc le poids effectif du tableau en mémoire est de deux fois sa longueur. Enfin, la classe String est un objet et non pas un primitif, donc chaque instance de cette classe porte avec elle un poids supplémentaire en mémoire en sus de celui du tableau de caractères.
Attention : si vous manipulez des chaînes (modification, concaténation, etc.) et à plus forte raison des chaînes de grande taille, vous devez utiliser des java.lang.StringBuffer, java.lang.StringBuilder ou des mécanismes similaires qui vous éviteront de créer des chaines intermédiaires sans prendre garde.
En Java, une instance de la classe String est dite immuable ou non-mutable, c'est-à-dire qu'après avoir été créée, la chaîne ne peut plus être modifiée. Cela s'avère très pratique dans beaucoup de situations : inutile par exemple de dupliquer une instance de String pour s'assurer qu'elle restera constante (comme c'est le cas en C++ par exemple). Mais cette propriété se révèle désastreuse avec l'emploi de l'opérateur + pour la concaténation de chaînes, car chaque étape de la concaténation implique la construction d'une nouvelle instance de String.
Code Java : | Sélectionner tout |
1 2 3 4 5 | String resultat = ""; // Création d'une chaîne de caractères vide. for( int i=0; i<10; i++) { resultat = resultat + i; } System.out.println(resultat); // "0123456789" |
Lors de l’exécution de ce programme, chaque itération de la boucle construit une nouvelle instance de String. Chaque itération oblige donc la JVM à trouver de la place en mémoire, instancier l'objet, copier le contenu des deux chaînes de caractères dans la nouvelle, libérer la mémoire, recommencer à l'itération suivante. Cela revient à créer 10 instances de String pour les résultats intermédiaires.
Comme nous venons de le voir, l'utilisation de l’opérateur + est déconseillée lorsque nous devons concaténer des chaînes de caractères entre elles. L'API Java offre plusieurs mécanismes permettant d'effectuer la concaténation de manière plus efficace : java.lang.StringBuilder, java.lang.StringBuffer, java.io.StringWriter, java.util.StringJoiner, java.util.Formatter, java.text.MessageFormat, etc.
StringBuilder et StringBuffer
Ces deux classes gèrent une chaîne modifiable. Elles ont a été spécialement conçues pour manipuler des chaînes de caractères et présentent toutes les deux des API compatibles.
- java.lang.StringBuffer - présente depuis Java 1.0, ses méthodes sont synchronisées et sont donc thread-safe. Elle peut donc être utilisée dans un environnement où plusieurs threads vont composer la chaîne de caractères ;
- java.lang.StringBuilder - présente depuis Java 1.5, ses méthodes ne sont pas synchronisées. Elle offre donc les meilleures performances, mais doit être utilisée dans un environnement mono-thread. Il s'agit de la classe que vous serez amené à utiliser le plus souvent.
Comme ces deux classes partagent la même API, le nom des deux classes est interchangeable dans le code suivant :
Code Java : | Sélectionner tout |
1 2 3 4 5 | StringBuilder sb = new StringBuilder(20); // 20 = une estimation de la taille maximale de notre chaîne. for (int i = 0 ; i < 10 ; i++) { sb.append(i); } System.out.println(sb.toString()); // "0123456789" |
Ce code produit exactement le même résultat que le précédent, sauf qu'il instancie un seul objet là où dix étaient nécessaires.
Note :
Si vous ne précisez pas la taille maximale ou que vous sous-estimez cette taille, StringBuffer/StringBuilder recréera automatiquement son tableau de caractères pour pouvoir accueillir votre texte, mais cette option est aussi coûteuse que la création d'une instance de String, il convient donc de choisir intelligemment cette valeur.
StringWriter
La classe java.io.StringWriter permet de manipuler un java.io.Writer qui génère une String. Elle peut donc être utilisée dans tout code qui manipule des flux de sortie avec des instances spécialisées de Writer. Elle fonctionne de manière similaire à StringBuffer/StringBuilder.
StringJoiner
La classe StringJoiner apparue depuis Java 8 permet de concaténer des chaînes de caractères en spécifiant un délimiteur. Il peut être précisé également lors de la construction d'un objet StringJoiner un préfixe et un suffixe.
Code java : | Sélectionner tout |
1 2 3 4 | StringJoiner sj = new StringJoiner(":", "[", "]"); sj.add("bouye").add("clement").add("mickael"); String maChaine = sj.toString(); // [bouye:clement:mickael] |
Formatter, String.format(), PrintStream.printf(), PrintWriter.printf() et Console.printf()
La classe java.util.Formatter introduite dans le JDK 1.5 permet de substituer des jetons dans une chaîne par des valeurs (autre chaîne, nombre, date, etc.). en suivant une syntaxe similaire à celle de la fonction printf() en langage C. Cette syntaxe est décrite dans la page Javadoc de la classe Formatter. De plus, la méthode format() de la classe String ainsi que les méthodes printf() de certaines classes de flux et de writer acceptent également des arguments et syntaxes identiques. Il est donc possible de les utiliser pour concaténer des chaînes entre elles.
Code Java : | Sélectionner tout |
String result = String.format("%s%s%s", "Salut", " ", "le monde !");
MessageFormat
La classe java.text.MessageFormat introduite dans le JDK 1.1 permet de substituer des jetons dans une chaîne par des valeurs (autre chaîne, nombre, date, etc.). La syntaxe à utiliser est propre à cette classe et est décrite dans sa page Javadoc. Il est donc possible de l'utiliser pour concaténer des chaînes entre elles.
Code Java : | Sélectionner tout |
String result = MessageFormat.format("{0}{1}{2}", "Salut", " ", "le monde !");
Il arrive assez souvent qu'il soit nécessaire de concaténer des valeurs contenues dans un tableau, une collection ou accessibles par un itérateur dans une chaîne de caractères en utilisant un séparateur donné ; par exemple si vous devez écrire dans un fichier au format CSV ou encore lors de la construction des paramètres pour effectuer une requête SQL ou sur un site web. Il existe plusieurs manières de procéder à une telle construction :
Boucle for, while ou do-while
Cette manière classique de faire va itérer sur les valeurs contenues dans la source (ici un tableau) pour insérer le séparateur entre chaque valeur en prenant soin d’éviter de mettre un séparateur en fin de chaîne. Les valeurs sont insérées dans une instance de StringBuilder pour éviter de construire plein de petites chaînes intermédiaires.
Code Java : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 | String separateur = ","; int[] valeurs = { 0, 1, 2, 3, 4 }; StringBuilder tampon = new StringBuilder(); for (int index = 0 ; index < valeurs.length ; index++) { tampon.append(valeurs[index]); if (index != valeurs.length - 1) { tampon.append(separateur); // Insertion du séparateur. } } String chaine = tampon.toString(); |
Ou :
Code Java : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 | String separateur = ","; int[] valeurs = { 0, 1, 2, 3, 4 }; StringBuilder tampon = new StringBuilder(); tampon.append(valeurs[0]); // Insertion de la première valeur. for (int index = 1 ; index < valeurs.length ; index++) { tampon.append(separateur); // Insertion du séparateur. tampon.append(valeurs[index]); } String chaine = tampon.toString(); |
Boucle for-each
À partir du JDK 5, il est également possible d'utiliser une boucle for-each pour effectuer le traitement. Ici, on prendra soin d'enlever le dernier séparateur qui a été inséré en fin de chaîne :
Code Java : | Sélectionner tout |
1 2 3 4 5 6 7 8 | String separateur = ","; int[] valeurs = { 0, 1, 2, 3, 4 }; StringBuilder tampon = new StringBuilder(); for (int valeur : valeurs) { tampon.append(valeur); tampon.append(separateur); // Insertion du séparateur. } String chaine = (tampon.length() == 0) ? "" : tampon.substring(0, tampon.length() - separateur.length()); // On enlève le dernier séparateur. |
Méthode join()
À partir du JDK 8, il est possible d'utiliser la méthode publique statique join() de la classe String pour concaténer un tableau ou une collection de chaînes de caractères :
Code Java : | Sélectionner tout |
1 2 3 | String separateur = ","; String[] valeurs = { "0", "1", "2", "3", "4" }; String chaine = String.join(separateur, valeurs); |
Streams
À partir du JDK 8, il est possible d'utiliser les streams pour effectuer cette opération de manière bien plus concise lorsque vos valeurs ne sont pas des chaînes de caractères :
Code Java : | Sélectionner tout |
1 2 3 4 5 | String separateur = ","; int[] valeurs = { 0, 1, 2, 3, 4 }; String chaine = Arrays.stream(valeurs) .mapToObject(String::valueOf) .collect(Collectors.joining(separateur)); |
Opérateur ==
Avant d'essayer de comparer deux chaînes de caractères, il faut bien comprendre que l'opérateur == permet de comparer entre eux les types primitifs (int, float, boolean, etc. ) mais que, dans le cas des objets, cet opérateur compare les emplacements mémoire des objets. Deux instances d'une classe, même initialisées avec les mêmes paramètres, occupent des espaces mémoire différents, elles sont donc différentes du point de vue de l’opérateur ==.
De manière générale, il ne faut donc pas utiliser cet opérateur pour comparer deux chaînes de caractères entre elles !
La méthode equals()
L'opération qui permet de comparer les objets entre eux est la méthode equals() de la classe java.lang.Object.
Code Java : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | String a = "coucou"; String b = "coucou"; String c = "bonjour"; String d = c; boolean test1 = a == b; /** * FAUX, a et b sont des instances différentes de String. * Ce résultat est théorique, car certains compilateurs pourraient optimiser * le code pour ne créer qu'une seule instance mémoire. */ boolean test2 = a.equals(b); // VRAI, equals() compare les chaînes caractère par caractère. c == d; // VRAI, c et d représentent la même instance mémoire de String |
Méthode de la classe Objects
À partir du JDK 7, vous pouvez utiliser la méthode statique equals() de la classe utilitaire java.util.Objects pour faire une comparaison sûre entre deux objets :
Code Java : | Sélectionner tout |
boolean test = Objects.equals(a, b);
Cette comparaison ne peut pas générer d'exception de type NullPointerException.
La méthode intern()
L'usage de la méthode intern() vient un peu compliquer la chose en conservant une liste privée d'instances de String. Initialement, la liste est vide. L'appel de la méthode intern() cherche dans la liste si une instance est égale d'après equals(), si oui, cette instance est retournée, sinon la chaîne est ajoutée à la liste.
Code java : | Sélectionner tout |
1 2 3 4 5 6 | String a = "coucou"; // 1re instance. String b = "coucou"; // 2e instance. a = a.intern(); // l'instance 1 est ajoutée à la liste, 'a' ne change pas de valeur. b = b.intern(); // Équivalent à : b = a; a == b; // VRAI. |
Comparaison lexicographique
De plus, la classe String dispose de plusieurs méthodes qui permettent de comparer des chaînes entre elles de manière lexicographique :
- compareTo() - cette méthode fait une comparaison lexicographique entre la chaîne actuelle et une seconde chaîne passée en paramètre. Elle retourne 0 si les deux chaînes sont identiques, un nombre positif si la chaîne actuelle est « plus grande » que le paramètre ou un nombre négatif si la chaîne actuelle est « plus petite » que le paramètre.
Code Java : Sélectionner tout int result = "toto".compareTo("tutu");
- compareToIgnoreCase() - la comparaison s'effectue de manière lexicographique, mais le résultat de cette méthode ignore la casse (majuscules/minuscules) des deux chaînes.
Code Java : Sélectionner tout int result = "toto".compareToIgnoreCase("Toto"); // Retourne 0.
Ce code est en fait équivalent au code suivant :Code Java : Sélectionner tout int result = "toto".toUpperCase().compareTo("Toto".toUpperCase()); // Retourne 0.
Qui est lui-même équivalent à :Code Java : Sélectionner tout int result = "TOTO".compareTo("TOTO"); // Retourne 0.
Attention toutefois, ces comparaisons lexicographiques ignorent totalement les règles potentiellement définies par les locales (langue et pays).
Par défaut, toutes les opérations de comparaison et égalité des chaînes de caractères se basent sur leurs valeurs Unicode. Cela permet des traitements très rapides, car il s'agit d'une comparaison bit à bit, mais cela produit des résultats non souhaitables avec certaines locales...
Prenons par exemple le code suivant qui permet de trier une liste et de l'afficher :
Code Java : | Sélectionner tout |
1 2 3 4 5 6 7 | List<String> list = new ArrayList<String>(); list.add("oxygène"); list.add("où"); list.add("ou"); Collections.sort(list); System.out.println(list); |
Code Console : | Sélectionner tout |
[ou, oxygène, où]
Ce résultat est dû au fait que le tri s'effectue sur la valeur Unicode des caractères. Or le caractère 'ù' prend la valeur 249 alors que 'u' et 'x' ont respectivement les valeurs 117 et 120. Ce qui fait que le caractère 'x' vient s'intercaler entre les caractères 'u' et 'ù', ce qui peut être gênant dans une langue comme le français où les accents ont une certaine importance.
Pour remédier à cela, il faut utiliser la classe Collator, qui permet d'effectuer des comparaisons en prenant en compte la locale :
Code Java : | Sélectionner tout |
Collections.sort(list, Collator.getInstance(Locale.FRANCE));
La méthode statique Collator.getInstance() permet de créer une nouvelle instance de Collator pour la locale courante. Le Collator implémente l'interface Comparable afin de comparer les chaînes de caractères.
De plus, les instances de Collators permettent également de fixer des contraintes plus ou moins fortes concernant la comparaison des caractères, et permettent de définir quatre niveaux via la méthode setStrength() :
- Collator.IDENTICAL - les caractères doivent être strictement identiques ;
- Collator.TERTIARY - diminue les contraintes de IDENTICAL en ignorant les différences sur les caractères de contrôle (ex. : \u0001 == \u0002) ;
- Collator.SECONDARY - diminue les contraintes de TERTIARY en ignorant les différences de casse minuscules/majuscules (ex. : 'a' == 'A') ;
- Collator.PRIMARY - diminue les contraintes de TERTIARY en ignorant les accents (ex. : 'a' == 'à' == 'â' == 'ä' == 'A' == 'Ä' etc.).
Attention toutefois, étant donné que les Collators se basent sur des règles plus complexes, ils peuvent prendre plus de temps que la comparaison standard des chaînes.
Selon votre version de Java et vos besoins, il y a plusieurs solutions possibles à cet épineux problème.
La classe Normalizer
Avec Java 6, il est possible d'utiliser la classe java.text.Normalizer afin de décomposer le codage Unicode des accents en deux « caractères » :
- le premier caractère correspond à la lettre sans aucune accentuation ;
- le second caractère est un « diacritique », c'est-à-dire un signe qui s'ajoute au caractère auquel il est associé.
Ces caractères diacritiques font partie de la plage Unicode 0300-036F. Il est donc possible de les supprimer assez facilement avec une expression régulière, par exemple :
Code Java : | Sélectionner tout |
1 2 3 4 | public static String sansAccents(String source) { String normalized = Normalizer.normalize(source, Normalizer.Form.NFD); return normalized.replaceAll("[\u0300-\u036F]", ""); } |
Ou encore :
Code Java : | Sélectionner tout |
1 2 3 4 5 | public static String sansAccents(String source) { final String normalized = Normalizer.normalize(source, Normalizer.Form.NFD); final Pattern pattern = Pattern.compile("\\p{InCombiningDiacriticalMarks}+"); return pattern.matcher(normalized).replaceAll(""); } |
Malheureusement, cette classe n'est pas présente sous cette forme dans l'API des versions précédentes de Java. En effet cette classe faisait partie de l'API propriétaire de Sun. S'il est toutefois possible de l'utiliser, il faut bien prendre en compte qu'il s'agissait d'une classe « non standard/portable » qui pourrait très bien ne pas exister dans une autre JVM, et qu'il est donc fortement conseillé de ne pas utiliser.
La bibliothèque tierce ICU4J
Une autre solution consiste à utiliser une bibliothèque externe comme ICU4J :
Code Java : | Sélectionner tout |
1 2 3 4 | public static String sansAccents(String s) { Transliterator accentsconverter = Transliterator.getInstance("NFD; [:M:] Remove; NFC; "); return accentsconverter.transliterate(s); } |
Il s'agit toutefois d'une bibliothèque assez volumineuse (plus de 4 Mo dans sa dernière version).
Modification manuelle
Enfin la dernière solution consiste tout simplement à coder manuellement une classe prévue à cet effet, comme cet exemple dans les sources Java : Supprimer les accents d'une chaîne
Pour faire cela, on peut utiliser le constructeur de String prenant en paramètre un tableau de byte ainsi que l'encodage à utiliser.
Voici un exemple permettant de convertir une chaîne codée en UTF-8 en ISO-8859-1 (Latin 1, français) :
Code Java : | Sélectionner tout |
1 2 | byte[] bytesUTF8 = ... ; byte[] bytesISO = new String(bytesUTF8, "ISO-8859-1").getBytes(); |
Il existe bien des manières de convertir des objets quelconques en chaine de caractères, par exemple, en utilisant des classes de conversion ou de formatage destinées à des usages très particuliers et spécialisés (ex. : formatage des nombres, durées, temps, dates ou monnaies en fonction de la langue, conversion en XML, etc.). C'est pourquoi nous allons uniquement aborder ici les méthodes les plus simples pour procéder à une telle conversion.
Méthode toString()
Il s'agit de la méthode la plus simple pour convertir un objet quelconque en chaine de caractères : la classe java.lang.Object définit la méthode publique toString() qui renvoie une représentation de l'objet sous forme de String. Donc il est possible d'invoquer cette méthode sur n'importe quel objet Java.
Dans l'API cette représentation peut varier beaucoup d'une classe à une autre. Il n'y a pas vraiment de règle préétablie et chaque cas est différent :
- par défaut, dans la classe Object, cette méthode renvoie l’équivalent de getClass().getName() + '@' + Integer.toHexString(hashCode()), par exemple : Voiture@7AC123 ;
- d'autres classes comme les collections, les couleurs ou encore les composants d'affichage Swing peuvent renvoyer une version formatée des valeurs qu'elles contiennent.
Par exemple :Code Java : Sélectionner tout 1
2
3
4List<Integer> list = Arrays.asList(0, 1, 2, 3); System.out.println(list); JLabel label = new JLabel("toto"); System.out.println(label);
Ce qui affichera :Code Console : Sélectionner tout 1
2[0, 1, 2, 3] javax.swing.JLabel[,0,0,0x0,invalid,alignmentX=0.0,alignmentY=0.0,border=,flags=8388608,[...]
Vous êtes totalement libre de surcharger cette méthode pour vos classes personnalisées ou qui étendent des classes de l'API de manière à retourner la valeur qui vous convient :
Code Java : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 | public class Personne { private String nom; private String prenom; [...] @Override public String toString() { String resultat = prenom + " " + nom; return resultat; } } |
Ou :
Code Java : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 | public class Personne { private String nom; private String prenom; [...] @Override public String toString() { StringBuilder resultat = new StringBuilder().append(prenom).append(" ").append(nom); return resultat.toString(); } } |
Et plus tard :
Code Java : | Sélectionner tout |
1 2 3 4 | Personne personne = [...] System.out.println(personne.toString()); // Ou System.out.println(personne); // La méthode toString() sera invoquée de manière implicite. La chaine "null" sera affichée si personne est nulle. |
Ce qui pourra afficher :
Code Console : | Sélectionner tout |
Jean Durant
Méthodes de la classe Objects
Depuis le JDK 7, il est possible d'invoquer une des variantes de la méthode publique statique toString() de la classe utilitaire java.util.Objects. Cette méthode permet de faire une conversion sûre sans provoquer d'exception de type NullPointerException dans le cas où la référence testée est à la valeur null. Lorsque la référence n'est pas nulle, sa méthode toString() sera invoquée.
Par exemple, le code suivant n'est pas vraiment sûr :
Code Java : | Sélectionner tout |
String chaine = personne.toString(); // Peut provoquer une NullPointerException si personne est nulle.
Mais il est possible de le remplacer par :
Code Java : | Sélectionner tout |
String chaine = Objects.toString(personne); // Renvoie "null" si personne est nulle.
Ou :
Code Java : | Sélectionner tout |
String chaine = Objects.toString(personne, "Pas de valeur"); // Renvoie "Pas de valeur" si personne est nulle.
JDK 1.0 :
Il faut utiliser un objet java.util.StringTokenizer qui permet aisément de découper une chaîne en sous-chaînes séparées par des délimiteurs que l'on peut préciser.
Code Java : | Sélectionner tout |
1 2 3 4 5 | String maChaine = "Salut le monde !"; final StringTokenizer tokenizer = new StringTokenizer(maChaine, " "); while (tokenizer.hasMoreTokens()) { System.out.println(tokenizer.nextToken()); } |
JDK 1.4 :
Le JDK 1.4 apporte la gestion des expressions régulières, le découpage d'une chaîne est maintenant possible directement de la classe java.lang.String grâce à la méthode split() qui prend en paramètre une expression régulière.
Code Java : | Sélectionner tout |
1 2 3 4 5 | String maChaine = "Salut le monde !"; String[] tokens = maChaine.split("\\s+"); for (String token : tokens) { System.out.println(token); } |
Proposer une nouvelle réponse sur la FAQ
Ce n'est pas l'endroit pour poser des questions, allez plutôt sur le forum de la rubrique pour çaLes sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2024 Developpez Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.