Découvrir les Types de données primitifs

Types de données primitifs

Java est un langage fortement typé. Cela signifie que chaque variable doit avoir un type déclaré. Il y a huit types primitifs en Java. Quatre d’entre eux sont des types entiers ; deux sont des types de nombres à virgule flottante ; un est le type caractère (char), utilisé pour les unités de code dans le schéma de codage Unicode (voir la section sur le type char), et un est le type booléen pour les valeurs de vérité (vrai/faux).

Java a un paquet arithmétique de précision arbitraire (arbitrary-precision arithmetic package). Cependant, les ” gros nombres “, comme on les appelle, sont des objets Java et non un type Java primitif. Vous verrez comment les utiliser plus loin dans l’article Gros nombres.

Types de nombres entiers

Les types entiers sont conçus pour les nombres sans parties fractionnaires. Les valeurs négatives sont autorisées. Java fournit les quatre types d’entiers indiqués dans le tableau A.

Tableau A – Types d’entiers Java

TypeExigences en matière de stockagePlage (Inclusive)
int4 bytes–2,147,483,648 à 2,147,483,647
short2 bytes–32,768 à 32,767
long8 bytes–9,223,372,036,854,775,808  à 9,223,372,036,854,775,807
byte1 byte–128 à 127

 

Dans la plupart des situations, le type int est le plus pratique. Si vous voulez représenter le nombre d’habitants de notre planète, il vous faudra recourir au type long.

Les types byte et short sont principalement destinés à des applications spécialisées, telles que la gestion de fichiers de bas niveau, ou pour les grands tableaux lorsque l’espace de stockage est limité.

Sous Java, les plages de valeurs des types entiers ne dépendent pas de la machine sur laquelle vous allez exécuter le code Java.

Ceci permet d’alléger une douleur majeure pour le programmeur qui veut déplacer un logiciel d’une plate-forme à l’autre, ou même d’un système d’exploitation à un autre sur la même plate-forme physique.

En revanche, les programmes C et C++ utilisent le type d’entier le plus efficace pour chaque processeur. En conséquence, un programme C qui fonctionne bien sur un processeur 32 bits peut présenter un débordement d’entier sur un système 16 bits.

Comme les programmes Java doivent fonctionner avec les mêmes résultats sur toutes les machines, les plages de valeurs pour les différents types sont fixes.

Les nombres entiers longs ont un suffixe L ou l (par exemple, 4000000000L). Les nombres hexadécimaux ont un préfixe 0x ou 0X (par exemple, 0xCAFE).

Les nombres octaux ont un préfixe 0 (par exemple, 010 est 8) -naturellement, cela peut engendrer une confusion, nous vous recommandons donc de ne pas utiliser des constantes octales.

A partir de Java 7, vous pouvez écrire des nombres en binaire, avec un préfixe 0b ou 0B. Par exemple, 0b1001 est égal à 9 et à partir de Java 7, vous pouvez ajouter des traits de soulignement aux nombres, comme 1_000_000 (ou 0b1111_0100_0010_0100_0000) pour indiquer 1 million.

Les soulignements sont pour les yeux humains seulement. Le compilateur Java les supprime tout simplement.

En C et C++, la taille des types tels que int et long dépend de la plate-forme cible. Sur un processeur 16 bits tel que le 8086, les entiers sont de 2 octets, mais sur un processeur 32 bits comme un Pentium ou un SPARC ils sont de 4 octets.

De même, les valeurs de type long sont de 4 octets sur les processeurs 32 bits et de 64 bits sur les processeurs 64 bits. Ces différences font qu’il est difficile d’écrire des programmes multi-plateformes. En Java, les tailles de tous les types numériques sont indépendantes de la plate-forme.

Notez que Java n’a pas de versions non signées des types int, long, short ou byte.

Si vous travaillez avec des valeurs entières qui ne peuvent jamais être négatives et que vous avez vraiment besoin d’un bit supplémentaire, vous pouvez, avec un certain soin, interpréter les valeurs entières signées comme non signées.

Par exemple, au lieu d’avoir un octet b représentant la plage de -128 à 127, vous voulez peut-être une plage de 0 à 255. Vous pouvez le stocker dans un octet.

En raison de la nature de l’arithmétique binaire, l’addition, la soustraction et la multiplication fonctionneront si elles ne débordent pas.

Pour les autres opérations, vous pouvez appeler la méthode Byte.toUnsignedInt(b) pour obtenir une valeur int comprise entre 0 et 255, puis traiter la valeur entière et la ramener à byte. Les classes Integer et Long ont des méthodes pour la division non signée et le reste.

Types à virgule flottante

Les types à virgule flottante désignent des nombres avec des parties fractionnaires. Les deux types de virgule flottante sont présentés dans le tableau B.

Tableau B – Types à virgule flottante

TypeExigences en matière de stockagePlage
float4 bytesEnviron ±3.40282347E+38F (6 -7 chiffres décimaux significatifs)
double8 bytesApproximately ±1.79769313486231570E+308 (15 chiffres décimaux significatifs)

 

Le nom double fait référence au fait que ces nombres sont deux fois plus précis que le type float. La précision limitée de float (6-7 chiffres significatifs) n’est tout simplement pas suffisante pour de nombreuses situations. N’utilisez les valeurs flottantes que lorsque vous travaillez avec une bibliothèque qui en a besoin ou lorsque vous devez en stocker un très grand nombre.

Les nombres du type float ont un suffixe F ou f (par exemple, 3.14F). Les nombres à virgule flottante sans suffixe F sont toujours considérés comme étant de type double. Vous pouvez fournir en option le suffixe D ou d (par exemple, 3.14D).

Vous pouvez spécifier les littéraux à virgule flottante en hexadécimal. Par exemple, 0,125 = 2-3 peut être écrit comme 0x1.0p-3. En notation hexadécimale, vous utilisez un p, et non un e, pour désigner l’exposant. (Un e est un chiffre hexadécimal.) Notez que la mantisse est écrite en hexadécimal et l’exposant en décimal. La base de l’exposant est 2, pas 10.

Tous les calculs en virgule flottante suivent la spécification IEEE 754. En particulier, il existe trois valeurs spéciales à virgule flottante pour indiquer les débordements et les erreurs :
– Infini positif
– Infini négatif
– NaN (pas un nombre)

Par exemple, le résultat de la division d’un nombre positif par 0 est l’infini positif. Calculer 0/0 ou la racine carrée d’un nombre négatif donne NaN.

Les constantes Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY et Double.NaN (ainsi que les constantes Float correspondantes) représentent ces valeurs spéciales, mais elles sont rarement utilisées en pratique. En particulier, vous ne pouvez pas tester

if (x === Double.NaN) // n’est jamais vrai

pour vérifier si un résultat particulier est égal à Double.NaN. Toutes les valeurs “pas un nombre” sont considérées comme distinctes. Cependant, vous pouvez utiliser la méthode Double.isNaN :

if (Double.isNaN(x)) // Vérifier si x n’est pas “pas un nombre”.

Les nombres à virgule flottante ne conviennent pas aux calculs financiers dans lesquels les erreurs d’arrondi ne peuvent être tolérées. Par exemple, la commande System.out.println(2.0 – 1.1) imprime 0.8999999999999999, et non pas 0.9 comme prévu.

De telles erreurs d’arrondi sont dues au fait que les nombres à virgule flottante sont représentés dans le système de nombres binaires.

Il n’y a pas de représentation binaire précise de la fraction 1/10, tout comme il n’y a pas de représentation précise de la fraction 1/3 dans le système décimal.

Si vous avez besoin des calculs numériques précis sans erreurs d’arrondi, utilisez la classe BigDecimal, qui est présentée dans un article séparé sur ce site.

Le type char

À l’origine, le type caractère (char) était destiné à décrire des caractères individuels. Or, ce n’est plus le cas aujourd’hui. De nos jours, certains caractères Unicode peuvent être décrits avec une valeur char, et d’autres caractères Unicode nécessitent deux valeurs char.

Les valeurs littérales de type char sont placées entre guillemets simples. Par exemple, ‘A’ est une valeur constante de caractère avec la valeur 65. Elle est différente de “A”, une chaîne de caractères contenant un seul caractère.

Les valeurs de type char peuvent être exprimées en valeurs hexadécimales qui vont de \u0000 à \uFFFF. Par exemple, \u2122 est le symbole de la marque (™) et \u03C0 est la lettre grecque pi (π).

Outre les séquences d’échappement \u, il existe plusieurs séquences d’échappement pour les caractères spéciaux, comme indiqué dans le tableau C. Vous pouvez utiliser ces séquences d’échappement à l’intérieur des littérales et chaînes de caractères entre guillemets telles que’\u2122′ ou “Hello\n”.

La séquence d’échappement \u (mais aucune des autres séquences d’échappement) peut même être utilisée en dehors des constantes et chaînes de caractères entre guillemets. Par exemple,

public static void main(String\u005B\u005D args)

est parfaitement légal car \u005B et \u005D sont les encodages de [ et ], respectivement.

Tableau C – Séquences d’échappement pour les caractères spéciaux

Séquence d’échappementNomValeur Unicode
\bRetour arrière\u0008
\tTabulation\u0009
\nSaut de ligne\u000a
\rRetour chariot\u000d
\”Guillemet\u0022
\’Guillemet simple\u0027
\\Barre oblique inverse\u005c

 

Les séquences d’échappement Unicode sont traitées avant l’analyse du code. Par exemple, “\u0022+\u0022″ n’est pas une chaîne composée d’un signe plus entouré de guillemets (U+0022). Au lieu de cela, les \u0022 sont convertis en ” avant d’analyser, donnant ” + “, ou une chaîne vide.

Encore plus insidieusement, tu dois te méfier de \u à l’intérieur des commentaires.

Le commentaire

// \u000A est une nouvelle ligne

donne une erreur de syntaxe puisque \u000A est remplacé par une nouvelle ligne lorsque le programme est lu. De même, un commentaire
// look inside c:\users

donne une erreur de syntaxe parce que le \u n’est pas suivi de quatre chiffres hexadécimaux.

L’Unicode et le type char

Pour bien comprendre le type char, vous devez connaître le schéma d’encodage Unicode. Unicode a été inventé pour surmonter les limites des schémas d’encodage de caractères traditionnels.

Avant Unicode, il existait de nombreux standards différents : ASCII aux États-Unis, ISO 8859-1 pour les langues d’Europe occidentale, KOI-8 pour le russe, GB18030 et BIG-5 pour le chinois, etc. Cela a causé deux problèmes. Tout d’abord, une valeur de code particulière correspond à des lettres différentes dans les différents schémas de codage.

Deuxièmement, les encodages pour les langues avec de grands jeux de caractères ont une longueur variable: Certains caractères communs sont codés en octets simples, d’autres nécessitent deux octets ou plus.

Unicode a été conçu pour résoudre ces problèmes. Lorsque l’effort d’unification a commencé dans les années 1980, un code fixe de 2 octets était plus que suffisant pour encoder tous les caractères utilisés dans toutes les langues du monde, avec de la place pour une extensibilité future, comme chacun l’avait alors cru à l’époque.

En 1991, Unicode 1.0 a été publié, utilisant un peu moins de la moitié des 65.536 valeurs de code disponibles.

Java a été conçu dès le départ pour utiliser des caractères Unicode 16 bits, ce qui représente une évolution majeure par rapport aux autres langages de programmation qui utilisent des caractères à 8 bits.

Malheureusement, avec le temps, l’inévitable s’est produit. Unicode a dépassé les 65 536 caractères, principalement grâce à l’ajout d’un très grand nombre de codes idéographiques utilisés pour le chinois, le japonais et le coréen.

Maintenant, le type de caractère à 16 bits est insuffisant pour décrire tous les caractères Unicode.

Nous avons besoin d’un peu de terminologie pour expliquer comment ce problème est résolu en Java, à commencer par Java 5. Un point de code est une valeur de code qui est associée à un caractère dans un schéma de codage.

Dans la norme Unicode, les points de code sont écrits en hexadécimal et préfixés avec U+, tel que U+0041 pour le point de code de la lettre latine A.

Unicode a des points de code qui sont regroupés en 17 plans de code. Le premier plan de codage, appelé plan multilingue de base, se compose des caractères Unicode “classiques” avec les points de codage U+0000 à U+FFFF.

Seize plans supplémentaires, avec les points de codage U+10000 à U+10FFFF, contiennent les caractères supplémentaires.

Le codage UTF-16 représente tous les points de code Unicode dans un code de longueur variable. Les caractères du plan multilingue de base sont représentés par des valeurs de 16 bits, appelées unités de code. Les caractères supplémentaires sont codés sous forme de paires consécutives d’unités de code.

Chacune des valeurs d’une telle paire de codage se situe dans une plage de 2048 valeurs inutilisées du plan multilingue de base, appelée zone des substituts (U+D800 à U+DBFF pour la première unité de code, U+DC00 à U+DFFF pour la deuxième unité de code).

C’est plutôt astucieux, car vous pouvez immédiatement savoir si une unité de code code représente un seul caractère ou s’il s’agit de la première ou de la deuxième partie d’un caractère supplémentaire.

Par exemple, (le symbole mathématique de l’ensemble des octonions) a le point de code U+1D546 et est codé par les deux unités de code U+D835 et U+DD46. (Voir https://tools.ietf.org/html/rfc2781 pour une description de l’algorithme d’encodage.)

En Java, le type de caractère décrit une unité de code dans l’encodage UTF-16.

Notre forte recommandation est de ne pas utiliser le type char dans vos programmes à moins que vous ne manipuliez des unités de code UTF-16. Il est presque toujours préférable de traiter les chaînes de caractères comme des types de données abstraites.

Le type boolean

Le type boolean a deux valeurs, false et true. Il est utilisé pour évaluer les conditions logiques. Vous ne pouvez pas convertir entre les entiers et les valeurs booléennes.

En C++, les nombres et même les pointeurs peuvent être utilisés à la place des valeurs booléennes. La valeur 0 est équivalente à la valeur false, et une valeur non nulle est équivalente à true. Ce n’est pas le cas en Java. Ainsi, les programmeurs Java sont protégés contre les accidents tels que

if (x = 0) // oops... signifie x == 0

En C++, ce test est compilé et exécuté, en l’évaluant toujours à false. En Java, le test ne se compile pas car l’expression entière x = 0 ne peut pas être convertie en valeur booléenne.

LAISSER UN COMMENTAIRE

Please enter your comment!
Please enter your name here