Accès rapide :
Méthodes de conversions pour vos types primitifs
Constantes et méthodes utilitaires
Auto-boxing et unboxing
Cas des collections génériques
Java est un langage « totalement » objet : il en résulte que la notion de fonction n'existe pas en tant que telle.
A la place, Java vous propose de coder des méthodes (statique ou non) : une méthode étant, en quelques sorte, une fonction, mais obligatoirement portée
par une classe. Il n'existe donc pas, en Java, de fonctions travaillant sur les types primitifs, comme cela peut être le cas en C :
à titre d'exemple le langage C fournit la fonction atoi
(Ascii TO Integer) pour transformer une chaîne en un nombre entier.
A la place il va nous falloir trouver des méthodes.
On le sait déjà, le package java.lang
propose un certain nombre de classes : java.lang.String
, java.lang.System
, ...
Mais nous l'avons aussi vu que dans ce même package se trouvent des classes associées aux types primitifs du langage Java : on parle de classes
enveloppantes (ou de Wrapper Classes en anglais). Ce sont ces classes qui portent des méthodes permettant certaines conversions
« primitif <=> chaînes de caractères ».
Le tableau suivant montre le lien entre chaque classe enveloppante et son type primitif associé ainsi que le nom des méthodes de conversion.
Classe enveloppante Wrapper class |
Type primitif associé | Méthode de conversion type primitif -> String |
Méthode statique de conversion String -> type primitif |
---|---|---|---|
java.lang.Byte | byte | String Byte.valueOf( value ).toString(); | static byte parseByte( String str ); |
java.lang.Short | short | String Short.valueOf( value ).toString(); | static short parseShort( String str ); |
java.lang.Integer | int | String Integer.valueOf( value ).toString(); | static int parseInt( String str ); |
java.lang.Long | long | String Long.valueOf( value ).toString(); | static long parseLong( String str ); |
java.lang.Float | float | String Float.valueOf( value ).toString(); | static float parseFloat( String str ); |
java.lang.Double | double | String Double.valueOf( value ).toString(); | static double parseDouble( String str ); |
java.lang.Boolean | boolean | String Boolean.valueOf( value ).toString(); | static boolean parseBoolean( String str ); |
java.lang.Character | char |
Le programme suivant vous montre comment utiliser quelques-unes de ces méthodes. On cherche à y ajouter tous les entiers passés en paramètres
du main
(donc à partir de la ligne commande). Or, args
est typé String []
: nos méthodes interviennent
à ce niveau-là, car on cherche à transformer les chaînes en valeurs entières et à les ajouter entre elles. Au final on transforme le résultat entier
en une chaîne de caractères (ce ne serait pas obligatoire, mais c'est pour l'exemple).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
public class Adder { public static void main( String [] args ) { int accumulator = 0; for( String param : args ) { accumulator += Integer.parseInt( param ); } String strAccumulator = Integer.valueOf( accumulator ).toString(); System.out.println( strAccumulator ); } } |
Et voici les résultats produit par ce programme
$> java Demo 10 20 30 60 $> java Demo 9 8 7 6 5 4 39 $>
accumulator
en une chaîne de caractère que l'on affiche en ligne 12.
Néanmoins, on aurait aussi pu remplacer la ligne 11 par ce code.
1 |
String strAccumulator = "" + accumulator;
|
Outre les méthodes relatives aux conversions de types, les classes enveloppantes proposent aussi tout un ensemble de constantes et de méthodes utilitaires pour manipuler les types associés. Nous en avons déjà vu un certain nombre dans les chapitres précédents.
Voici, pour rappel, quelques exemples de constantes que vous pouvez utiliser pour mieux connaître les bornes de vos types numériques entiers.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
public class Demo { public static void main( String [] args ) { System.out.println( Byte.MIN_VALUE ); System.out.println( Byte.MAX_VALUE ); System.out.println( Short.MIN_VALUE ); System.out.println( Short.MAX_VALUE ); System.out.println( Integer.MIN_VALUE ); System.out.println( Integer.MAX_VALUE ); System.out.println( Long.MIN_VALUE ); System.out.println( Long.MAX_VALUE ); } } |
Ce qui affiche :
-128 127 -32768 32767 -2147483648 2147483647 -9223372036854775808 9223372036854775807
Voici maintenant quelques exemples de méthodes utilitaires : elles sont souvent statiques, donc portées par vos classes enveloppantes.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
public class Demo { public static void main( String [] args ) { char theChar1 = 'e'; char theChar2 = '5'; System.out.println( Character.isDigit( theChar1 ) ); // false System.out.println( Character.isDigit( theChar2 ) ); // true System.out.println( Character.isLetter( theChar1 ) ); // true System.out.println( Character.isLetter( theChar2 ) ); // false System.out.println( Character.isLowerCase( theChar1 ) ); // true System.out.println( Character.isLowerCase( theChar2 ) ); // false System.out.println( Character.isUpperCase( theChar1 ) ); // false System.out.println( Character.isUpperCase( theChar2 ) ); // false System.out.println( Character.isSpaceChar( theChar1 ) ); // false System.out.println( Character.isSpaceChar( theChar2 ) ); // false System.out.println( Character.isSpaceChar( ' ' ) ); // true } } |
Bien que nous ayons déjà vu pas mal de choses sur ces classes enveloppantes, nous n'avons pas encore parlé de l'aspect le plus important.
Effectivement, ces classes enveloppantes n'exposent pas que des méthodes statiques. Elles permettent aussi de créer des instances (des objets)
qui vont pouvoir maintenir des valeurs. Par exemple, le code suivant permet de manipuler un entier, appelons le value
et il vaudra
123
: mais regardez bien le type de la variable.
1 2 3 4 5 6 7 8 9 10 11 |
public class Demo { public static void main( String [] args ) { // Integer value = new Integer( 123 ); // Possible, mais déprécié au profit de ... Integer value = Integer.valueOf( 123 ); System.out.println( value ); // affiche 123 } } |
Le code ci-dessus compile et s'exécute parfaitement depuis le JDK 1.0. Mais, avec le Java SE 5.0, les choses ont évoluées et la syntaxe s'en est trouvée largement simplifiée. Aujourd'hui, on peut écrire le programme ainsi.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
public class Demo { public static void main( String [] args ) { Integer value = 123; // Auto-boxing System.out.println( value ); // Affiche 123 // Il est même possible d'écrire value += 2; System.out.println( value ); // Affiche 125; } } |
Regardez bien la ligne 5, en fait elle est strictement équivalente à la ligne 6 de l'avant dernier exemple de code.
Le fait que l'appel à Integer.valueOf( 123 )
ne soit plus de votre responsabilité s'appelle « l'auto-boxing » :
le passage de la données brute dans une instance de la classe Integer est fait automatiquement.
Pour vous convaincre que l'appel est bien réalisé, voici le code désassemblé de la classe, via la commande javap -c
.
$> javap -c Demo Compiled from "Demo.java" public class Demo { public Demo(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return public static void main(java.lang.String[]); Code: 0: bipush 123 2: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; 5: astore_1 6: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream; 9: aload_1 10: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V 13: aload_1 14: invokevirtual #5 // Method java/lang/Integer.intValue:()I 17: iconst_2 18: iadd 19: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; 22: astore_1 23: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream; 26: aload_1 27: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V 30: return } $>
Du coup, la question que peut être vous vous posez est la suivante : peut-on indifféremment utiliser Integer value = 123;
ou
int value = 123;
? La réponse est NON ! Surtout pas. Pour des raisons que je vais passer pour le moment, disons simplement que
l'utilisation des types primitifs sera un peu plus efficace en termes de temps d'exécution.
De plus, les données basées sur les classes enveloppantes sont des objets : ils sont donc gérés par références. Au contraire les types primitifs sont gérés par valeurs (on dit aussi par copies). Ce point à aussi des conséquences en termes de performances.
Comme je viens de le dire, il est préférable d'utiliser les types primitifs pour vos variables, plutôt que des classes enveloppantes et ce notamment pour des raisons de performances. Pour autant, il y a un cas ou vous n'aurez pas le choix : l'utilisation de classes génériques sur des types numériques (par exemple, l'utilisation des collections Java).
Effectivement, la généricité Java ne permet de travailler que sur des objets et l'utilisation de types primitifs n'est pas supportée par le compilateur. Ce programme ne compile pas.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
import java.util.ArrayList; public class Demo { public static void main( String [] args ) { ArrayList<int> collection = new ArrayList<>(); collection.add( 10 ); collection.add( 20 ); collection.add( 30 ); for ( int value : collection ) { System.out.println( value ); } } } |
Et voici le message d'erreur produit par le compilateur.
$> javac Demo.java Demo.java:7: error: unexpected type ArrayList<int> collection = new ArrayList<>(); ^ required: reference found: int 1 error $>
Par contre, ce programme compile parfaitement.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
import java.util.ArrayList; public class Demo { public static void main( String [] args ) { ArrayList<Integer> collection = new ArrayList<>(); collection.add( 10 ); collection.add( 20 ); collection.add( 30 ); for ( int value : collection ) { System.out.println( value ); } } } |
Les lignes 8,9 et 10 font appel à l'auto-boxing : les valeurs typées int
sont automatiquement transformées en instances de la classe
java.lang.Integer
. La ligne 11 met en évidence le mécanisme inverse : l' « unboxing » qui permet l'extraction de la valeur
primitive contenue dans une instance enveloppante. L'utilisation du type int
devant la variable value
est donc tout à
fait légale.
Améliorations / Corrections
Vous avez des améliorations (ou des corrections) à proposer pour ce document : je vous remerçie par avance de m'en faire part, cela m'aide à améliorer le site.
Emplacement :
Description des améliorations :