Compréhension des types de données en Java

L’auteur a sélectionné le Fonds Libre et Open Source pour recevoir une donation dans le cadre du programme Write for DOnations.

Introduction

Java est un langage de programmation à typage statique. Cela signifie que lors de la création d’une variable, vous devez également spécifier son type de données, qui est le type d’information qu’elle stocke. Cela contraste avec les langages à typage dynamique, tels que PHP. Avec les langages à typage dynamique, vous n’avez pas à spécifier le type de données d’une variable, ce qui peut sembler être un soulagement.

Cependant, connaître les types de données et les utiliser de manière appropriée permet aux développeurs d’optimiser leur code car chaque type de données a des exigences de ressources spécifiques. De plus, si vous spécifiez un type de données et essayez d’en stocker un autre, par erreur par exemple, vous ne pourrez pas compiler le code. Ainsi, avec les langages à typage statique, vous pouvez détecter les erreurs même avant tout test.

Java possède deux types de données: primitifs et de référence (également connus sous le nom de non primitifs). Dans ce tutoriel, vous utiliserez des variables pour stocker et utiliser des informations dans un programme Java afin d’apprendre certains des types de données couramment utilisés en Java. Ce n’est pas un aperçu exhaustif de tous les types de données, mais ce guide vous aidera à vous familiariser avec les options disponibles pour vous en Java.

Prérequis

Pour suivre ce tutoriel, vous aurez besoin de:

Types Primitifs

Java Les types primitifs sont les types de données les plus simples et fondamentaux en Java. Ils représentent des valeurs brutes telles que des nombres et des caractères. Les types de données primitifs les plus fréquemment utilisés sont int (entiers), boolean (valeurs booléennes) et char (caractères). Vous pouvez trouver le reste dans la documentation officielle sur les types de données Java.

Entiers

Les entiers sont à la fois des nombres entiers négatifs et positifs. En Java, vous utiliserez int pour les stocker. int peut accommoder des nombres suffisamment grands pour la plupart des usages : de -2 147 483 648 à 2 147 483 647.

Jetons un coup d’œil à la manière dont int est utilisé dans un exemple :

int theAnswer = 42;

Les types primitifs commencent toujours par une lettre minuscule (int). Les règles de syntaxe Java exigent que vous spécifiiez d’abord le type de données (int) et ensuite son nom (theAnswer). Ensuite, vous attribuez la valeur 42 avec le signe égal (=) à la variable.

Quel que soit son type de données, vous utilisez une variable en spécifiant directement son nom sans ajouter de caractères spéciaux. Cela est possible car Java peut la reconnaître en tant que variable.

Remarque: Le nom de la variable theAnswer et de toutes les autres variables de ce tutoriel sont écrites en Camel case. Bien qu’il n’y ait pas d’exigence stricte à cet égard, c’est la convention de nommage acceptée en Java.

Une fois que vous avez déclaré la variable, vous pouvez l’utiliser en la référençant dans une méthode comme ceci:

int theAnswer = 42;
System.out.println("The answer to all questions is " + theAnswer);

Dans la deuxième ligne, vous affichez theAnswer dans la console en utilisant la méthode intégrée println du package System.out. C’est la manière la plus simple de tester une variable pour vérifier qu’elle est déclarée comme prévu.

Pour voir ce code en action, utilisez l’outil Java Shell. Après avoir installé Java, ouvrez un terminal ou une invite de commande sur votre ordinateur local et tapez jshell:

  1. jshell

Votre sortie ressemblera à ce qui suit:

Output
| Welcome to JShell -- Version 11.0.16 | For an introduction type: /help intro jshell>

Vous pouvez coller les exemples de code de ce tutoriel dans la console. Une fois terminé, vous pouvez quitter jshell en tapant /exit.

Pour déclarer et utiliser int, collez les lignes suivantes dans la console jshell:

  1. int theAnswer = 42;
  2. System.out.println("The answer to all questions is " + theAnswer);

Vous verrez la sortie suivante:

Output
theAnswer ==> 42 The answer to all questions is 42

Cette sortie confirme que vous avez correctement défini la variable int theAnswer sur 42 (theAnswer ==> 42). Vous avez également réussi à utiliser theAnswer en le passant à une méthode, et la méthode a produit la valeur de variable attendue.

Les valeurs Boolean

Boolean sont true ou false. En Java, vous utiliserez boolean pour les stocker. Par exemple, créons une variable boolean définissant si Java est amusant ou non:

boolean isJavaFun = true;

Vous définissez la variable isJavaFun comme étant true. La valeur alternative boolean est false.

En utilisant la variable ci-dessus, vous pouvez imprimer la phrase Java is fun: true comme ceci:

  1. boolean isJavaFun = true;
  2. System.out.println("Java is fun: " + isJavaFun);

Exécuter ces lignes dans jshell produira la sortie suivante:

Output
isJavaFun ==> true Java is fun: true

Similaire à l’exemple avec int, la méthode println va imprimer l’argument fourni entre parenthèses. Le signe plus (+) concatène ou joint la chaîne « Java is fun:  » avec la variable isJavaFun de sorte qu’en réalité, il s’agit d’un seul argument – la chaîne, Java is fun: true.

Caractères

Pour stocker un seul caractère alphanumérique, vous utiliserez char. Par exemple:

char firstLetter = 'a';

Remarquez que la lettre a est entourée de guillemets simples. Les guillemets simples ne peuvent être utilisés que pour les valeurs char. Les guillemets doubles sont utilisés pour les chaînes de caractères, comme vous le verrez plus tard.

char ne semble pas être un type particulièrement utile car il est peu probable que vous ayez besoin d’une variable assignée à un seul caractère. Cependant, char est utilisé comme élément de base pour les classes de chaînes de caractères telles que String, qui sont essentiellement une collection de valeurs char.

Comme vous l’avez vu dans cette section, la déclaration et l’utilisation de variables de type primitif sont simples car elles représentent des valeurs simples telles que des entiers. Ces valeurs sont prêtes à être utilisées et ne nécessitent pas d’opérations supplémentaires telles que la création d’objets, l’appel de méthodes, etc.

Types de référence

Dans le premier tutoriel de cette série, Comment écrire votre premier programme en Java, vous avez appris que le code Java est organisé en classes et que ces classes sont utilisées comme des modèles pour créer des objets. Lorsque de tels objets sont assignés à des variables, vous pointez ou faites référence à ces objets. Dans ces cas, les variables sont classifiées comme des types de référence. Ces variables sont également connues sous le nom de non primitifs car les variables de type primitif ne peuvent pas pointer vers des objets.

Les objets sont puissants car ils ont des propriétés avancées et sont capables d’agir lorsque vous déclenchez leurs méthodes. Cependant, sans variables pointant vers eux, ces objets sont inaccessibles et pratiquement inutilisables. C’est pourquoi les variables de type référence sont essentielles à Java et à la programmation orientée objet dans son ensemble.

Remarque : Les types de référence pointent vers des objets créés à partir de classes. Pour éviter toute confusion, le type de référence et l’objet créé seront de la même classe dans les exemples suivants.

Cependant, dans les programmes complexes, ce cas de figure est rarement rencontré. En Java, une interface est un groupe d’exigences pour un comportement spécifique, et ces exigences peuvent être satisfaites par une ou plusieurs classes. Une classe qui satisfait les exigences d’une interface est dite implémenter cette interface. Ainsi, dans les programmes complexes, il est courant de déclarer une variable avec le type de référence d’une interface. De cette manière, vous spécifiez le comportement que votre variable doit présenter sans la lier à une implémentation concrète de ce comportement. Cela vous permet de changer facilement l’implémentation vers laquelle votre variable pointe sans avoir à modifier la manière dont la variable est utilisée. Ce concept complexe fait partie d’un sujet plus avancé sur l’héritage et le polymorphisme, qui fera l’objet d’un tutoriel séparé dans notre série sur Java.

Bien qu’il n’y ait que quelques types primitifs, les types de référence sont pratiquement illimités car il n’y a pas de limite au nombre de classes (et interfaces), et chaque classe représente un type de référence. Il existe de nombreuses classes intégrées en Java qui fournissent des fonctionnalités essentielles. Les plus utilisées se trouvent dans le package principal java.lang. Vous en passerez en revue certaines dans cette section.

La classe String

La classe String représente une combinaison de caractères qui forment une chaîne de caractères. Pour déclarer une String, ou toute autre variable de type référence, vous spécifiez d’abord son type suivi de son nom. Ensuite, vous lui attribuez une valeur avec le signe égal. Jusqu’à présent, c’est similaire à travailler avec des types primitifs. Cependant, les types de référence pointent vers des objets, vous devez donc créer un objet s’il n’en existe pas déjà un. Voici un exemple :

String hello = new String("Hello");

hello est le nom de la variable de type référence String. Vous l’assignez à un nouvel objet String. Le nouvel objet String est créé avec le mot-clé new suivi du nom de la classe — String dans ce cas. La classe String commence par une lettre majuscule. Par convention, toutes les classes et donc les types de référence commencent par une lettre majuscule.

Chaque classe a une méthode spéciale appelée un constructeur qui est utilisée pour créer de nouveaux objets. Vous pouvez invoquer ce constructeur en ajoutant des parenthèses (()) à la fin du nom de la classe. Le constructeur peut accepter des paramètres, comme dans l’exemple ci-dessus, où le paramètre "Hello" est appliqué au constructeur pour String.

Pour confirmer que la variable hello se comporte comme prévu, passez-la à nouveau à la méthode println comme ceci :

  1. String hello = new String("Hello");
  2. System.out.println(hello);

En exécutant ces lignes dans jshell, vous obtiendrez la sortie suivante :

Output
hello ==> "Hello" Hello

Cette fois, la sortie confirme que la variable hello est définie sur Hello. Ensuite, ce même Hello est imprimé sur une nouvelle ligne, confirmant que la méthode println() l’a traité.

Classes d’enveloppe

Dans la section précédente, vous avez travaillé avec le type de référence String, qui est fréquemment utilisé. D’autres types de référence populaires sont les enveloppes pour les types primitifs, appelées ainsi. Une classe d’enveloppe enveloppe ou contient des données primitives, d’où son nom. Tous les types primitifs ont des équivalents d’enveloppe, et voici quelques exemples :

  • Integer : Pour envelopper les valeurs int.
  • Character : Pour envelopper les valeurs char.
  • Boolean : Pour envelopper les valeurs boolean.

Ces enveloppes existent afin que vous puissiez améliorer une valeur primitive simple en un objet puissant. Chaque enveloppe a des méthodes prêtes à l’emploi liées aux valeurs qu’elle est conçue pour stocker.

À titre d’exemple, vous explorerez Integer. Dans la section précédente, vous avez créé un objet String avec le mot-clé new. Cependant, certaines classes fournissent, voire encouragent, l’utilisation de méthodes spéciales pour obtenir des objets à partir d’elles, et Integer en est une. Dans le cas de Integer, l’utilisation d’une méthode spéciale concerne principalement l’optimisation des ressources, mais dans d’autres cas, il pourrait s’agir de simplifier la construction d’objets complexes.

Dans l’exemple suivant, vous créez une variable Integer appelée theAnswer avec la valeur 42 en utilisant la méthode valueOf:

  1. Integer theAnswer = Integer.valueOf(42);
  2. System.out.println(theAnswer);

Dans jshell, vous obtiendrez la sortie suivante:

Output
theAnswer ==> 42 42

En invoquant la méthode valueOf(42) de la classe Integer, vous indiquez à Java de vous fournir un objet avec cette valeur. En coulisses, Java vérifiera s’il existe déjà un objet avec une telle valeur dans son cache. S’il existe, l’objet sera lié à la variable theAnswer. S’il n’y en a pas, un nouvel objet sera créé pour la variable theAnswer.

De nombreuses classes intégrées fournissent de telles méthodes pour des raisons de performances, et leur utilisation est recommandée, voire obligatoire. Dans le cas de Integer, vous pourriez toujours créer un objet avec le mot-clé new, mais vous obtiendrez un avertissement de dépréciation.

En plus de String et des wrappers, il existe également d’autres types de référence intégrés utiles, que vous pouvez trouver dans le résumé du package java.lang. Pour comprendre pleinement certains de ces types de référence plus avancés, une explication supplémentaire ou des connaissances préalables sont nécessaires. C’est pourquoi nous en couvrirons certains dans nos prochains tutoriels de la série Java.

Littéraux

Les littéraux représentent des valeurs fixes qui peuvent être utilisées directement dans le code et peuvent donc être assignées à la fois aux types primitifs et de référence. Il existe quelques types de littéraux, qui peuvent être catégorisés comme suit.

Littéraux de type primitif

Vous avez déjà utilisé quelques littéraux dans la section sur les types primitifs. Pour chaque type primitif, il existe un littéral, comme ceux de nos exemples: 42, 'a', et true. Les entiers tels que 42 sont des littéraux entiers. De même, les caractères tels que 'a' sont des littéraux de caractère, et true et false sont des littéraux booléens.

Les littéraux des types primitifs peuvent également être utilisés pour créer des valeurs pour les types de référence. Le littéral int a été utilisé pour créer un objet Integer avec le code Integer.valueOf(42). Il existe également une version abrégée pour cela, et vous pouvez assigner directement la valeur comme ceci :

Integer theAnswer = 42;

42 est un littéral entier, tout comme n’importe quel nombre entier, et vous pouvez l’assigner directement à la variable theAnswer sans aucune instruction supplémentaire. Il est courant de voir un Integer déclaré de cette manière car c’est pratique.

Cette approche abrégée fonctionne également pour d’autres littéraux de types primitifs et leurs types de référence correspondants tels que Boolean, par exemple :

Boolean isFun = true;

true est le littéral, qui est directement assigné à la variable isFun de type Boolean. Il existe également un littéral false, que vous pouvez assigner de la même manière.

Le littéral de chaîne de caractères

Il existe également un littéral spécial pour le type de référence String, et il est reconnu par les guillemets doubles entourant sa valeur. Dans cet exemple, c’est "Hello, World!" :

String helloWorld = "Hello, World!";

L’utilisation de littéraux est plus simple et plus courte, et c’est pourquoi de nombreux programmeurs le préfèrent. Cependant, vous pouvez toujours déclarer une variable String avec un nouvel objet String, comme vous l’avez déjà fait dans la section des types de référence.

Le littéral Null

Il y a un autre littéral important: null, qui représente l’absence d’une valeur ou la non-existence d’un objet. Null vous permet de créer un type de référence et de le pointer vers null au lieu de le pointer vers un objet. null peut être utilisé pour tous les types de référence mais pas pour les types primitifs.

Il y a une mise en garde avec le littéral null: vous pouvez déclarer des variables avec, mais vous ne pouvez pas utiliser ces variables tant que vous n’avez pas réassigné une valeur appropriée et non nulle. Si vous essayez d’utiliser une variable de type de référence avec une valeur null, vous obtiendrez une erreur. Voici un exemple:

  1. String initiallyNullString = null;
  2. System.out.println("The class name is: " + initiallyNullString.getClass());

Lorsque vous essayez d’exécuter ce code dans jshell, vous verrez une erreur similaire à la suivante:

Output
initiallyNullString ==> null | Exception java.lang.NullPointerException | at (#4:1)

En fonction de votre système d’exploitation et de votre version de Java, votre sortie peut différer.

L’erreur java.lang.NullPointerException est lancée parce que vous essayez d’invoker la méthode getClass() de String (qui retourne le nom de la classe) sur la variable initiallyNullString (qui pointe vers un objet nul).

Note: Pour simplifier, nous appelons java.lang.NullPointerException une erreur même si c’est techniquement une exception. Pour en savoir plus sur les exceptions et les erreurs, consultez le tutoriel, Gestion des exceptions en Java.

Pour corriger l’erreur, vous devez réaffecter la valeur de initiallyNullString comme ceci:

  1. String initiallyNullString = null;
  2. initiallyNullString = "not null any longer";
  3. System.out.println("The class name is: " + initiallyNullString.getClass());

Le nouveau code corrigé affichera la sortie suivante:

Output
initiallyNullString ==> null initiallyNullString ==> "not null any longer" The class name is: class java.lang.String

La sortie ci-dessus montre comment initiallyNullString est d’abord null, puis devient un nouvel objet String contenant "not null any longer". Ensuite, lorsque la méthode getClass() est invoquée sur l’objet instancié, vous obtenez java.lang.String, où String est le nom de la classe et java.lang est son package. Enfin, un message complet et significatif est imprimé: "Le nom de la classe est: class java.lang.String".

De telles déclarations de valeurs null sont plus courantes pour le code hérité. Elles ont été utilisées pour créer d’abord une variable, puis plus tard pour lui assigner sa vraie valeur, généralement en passant par une logique qui détermine cette dernière. Cependant, depuis la version 8 de Java, il existe un nouveau type de référence appelé Optionnel, qui est plus adapté aux cas où null a été utilisé auparavant.

Inférence de type de variable locale

Jusqu’à présent, vous avez utilisé certains des types de données courants en Java pour définir des variables. Cependant, Java 10 a introduit une nouvelle fonctionnalité appelée inférence de type de variable locale, qui vous permet d’utiliser le mot-clé var devant une nouvelle variable. Avec cette fonctionnalité, Java inférera (c’est-à-dire, devinera automatiquement) le type de données à partir du contexte local. L’inférence de type est controversée car elle contraste avec la verbosité précédemment expliquée de la définition des variables. Les avantages et les inconvénients d’une telle fonctionnalité sont discutables, mais le fait est que d’autres langages typés statiquement, tels que le C++, prennent en charge l’inférence de type.

En tout cas, l’inférence de type ne peut pas remplacer complètement l’utilisation des types de données car elle ne fonctionne qu’avec les variables locales, qui sont des variables à l’intérieur d’une méthode. Regardons un exemple avec var:

  1. var hello = "Hello";
  2. System.out.println(hello);

Vous déclarez la variable hello avec le mot-clé var afin d’instruire Java de détecter son type de données. Ensuite, vous l’imprimez dans la console de la manière habituelle pour confirmer qu’elle fonctionne comme prévu:

Ouput
hello ==> "Hello" Hello

Cet exemple fonctionnera tant que votre installation Java (plus précisément, le JDK) est supérieure à la version 10. Le mot-clé var n’est pas pris en charge dans les versions plus anciennes.

L’inférence de type se produit pendant le processus de compilation, c’est-à-dire lorsque vous compilez le code. Le processus de compilation transforme le code source en texte brut en code machine et applique diverses optimisations, y compris l’inférence de type. Cela garantit que la quantité correcte de mémoire système est disponible pour les variables dont le type est inféré. Ainsi, le code machine que vous exécutez après la compilation est entièrement optimisé, comme si vous aviez spécifié manuellement tous les types de données.

Dans cet exemple, le mot-clé var fonctionne car la variable est locale, et le type de données var ne fonctionne qu’avec les variables locales. Les variables locales sont définies à l’intérieur des méthodes et sont accessibles uniquement à l’intérieur des méthodes, c’est pourquoi elles sont appelées « locales ».

Pour montrer que var ne peut être utilisé que pour les variables locales, essayez de le placer en dehors de la méthode principale, comme ceci :

  1. public class Hello {
  2. var hello = "Hello";
  3. public static void main(String[] args) {
  4. // example code
  5. }
  6. }

Lorsque vous collez le code ci-dessus dans jshell, vous obtiendrez l’erreur suivante :

Output
| Error: | 'var' is not allowed here | var hello = "Hello"; | ^-^

var n’est pas autorisé ici car hello est en dehors d’une méthode et n’est plus considéré comme local. Ainsi, l’inférence de type ne fonctionne pas pour les variables non locales car le contexte ne peut pas être utilisé de manière fiable pour détecter le type de données.

Utiliser var peut être difficile et n’est pas nécessaire, mais vous risquez probablement de le rencontrer, il est donc utile de le connaître.

Mots-clés réservés

Lorsque vous déclarez des variables en Java, il y a une règle supplémentaire importante à connaître. Il existe des mots-clés réservés que vous ne pouvez pas utiliser comme noms de variables. Par exemple, vous ne pouvez pas déclarer une primitive de type int et l’appeler new comme ceci:

  1. int new = 1;

Si vous essayez cet exemple, vous obtiendrez des erreurs de compilation car new est un mot-clé réservé.

Output
| Error: | '.class' expected | int new = 1; | ^ | Error: | <identifier> expected | int new = 1; | ^ | Error: | '(' or '[' expected | int new = 1; | ^ | Error: | unexpected type | required: value | found: class | int new = 1; | ^--^ | Error: | missing return statement | int new = 1; | ^----------^

Le mot-clé new est utilisé pour créer de nouveaux objets et Java ne s’attend pas à le trouver à cette position. Dans la liste des erreurs dans la sortie précédente, la première partie est la plus importante:

Output
| Error: | '.class' expected | int new = 1; | ^

L’erreur '.class' expected signifie que lorsque vous utilisez le mot-clé new, Java s’attend à ce qu’une classe suive. À ce stade, Java n’est pas en mesure d’interpréter l’instruction et les autres erreurs suivent.

Le reste des mots-clés réservés, tels que abstract, continue, default, for et break, ont également des significations spécifiques en Java et ne peuvent pas être utilisés comme noms de variables. La liste complète des mots-clés réservés peut être trouvée sur la page Mots-clés du langage Java. Même si vous ne vous souvenez pas de tous les mots-clés réservés, vous pouvez utiliser les erreurs de compilation pour identifier le problème.

Conclusion

Dans ce tutoriel, vous avez appris les types de données primitifs et de référence en Java, qui est un sujet complexe mais essentiel. Prenez votre temps pour le pratiquer et passez en revue les exemples plus d’une fois. Essayez de changer certains types de données et valeurs. Soyez attentif aux moments où des erreurs sont générées et quand elles ne le sont pas afin de développer un sentiment d’exécution réussie du code.

Pour en savoir plus sur Java, consultez notre série Comment Coder en Java.

Source:
https://www.digitalocean.com/community/tutorials/understanding-data-types-in-java