FAQ Langage JavaConsultez toutes les FAQ

Nombre d'auteurs : 41, nombre de questions : 294, dernière mise à jour : 21 mars 2016  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.


SommaireBases du langageTableaux (14)
précédent sommaire suivant
 

Un tableau (ou array) est un type de stockage de données contigües similaire à ce qu'on peut trouver dans d'autres langages de programmation. Un tableau peut contenir des literals, des références d'objets, y compris des références vers d'autres tableaux. Un tableau contenant des références peut contenir la valeur null, un tableau contenant des literals ne le peut pas.

Attention : en Java, un tableau n'est pas un pointeur adressant un bloc mémoire arbitraire. Ici, il s'agit d'un objet qui hérite implicitement de la classe java.lang.Object et sur lequel il est même possible d'invoquer quelques méthodes (celles définies dans la classe Object) !

Mis à jour le 10 juillet 2015 bouye

Pour déclarer un tableau en Java, vous devez spécifier un type (soit primitif, soit objet) suivi de la notation [] (crochet ouvrant suivi de crochet fermant). Par exemple :

Code Java : Sélectionner tout
1
2
3
int[] tableauEntier; // un tableau d'entiers. 
String[] tableauChaine; // un tableau de chaînes de caractères. 
Voiture[] tableauVoiture; // un tableau d'instances de la classe Voiture.

Les variables ainsi déclarées sont automatiquement du type décrit, ainsi tableauEntier est de type int[], tableauChaine est de type String[] tandis que la variable tableauVoiture est de type Voiture[] même si Voiture est un type que vous avez créé.

Cependant, une telle variable n'est pas initialisée. Dans le cas d'une variable membre d'une classe, elle sera implicitement à la valeur null ; tandis que dans une méthode, le compilateur générera une erreur à cause du défaut d’initialisation. Pour initialiser un tableau, il faut l'allouer, ce qui peut être fait en invoquant l’opérateur new et en donnant une taille au tableau, soit via une constante entière, soit via une variable entière. Par exemple :

Code Java : Sélectionner tout
int[] tableauEntier = new int[10]; // Le tableau contiendra 10 éléments.

Attention cependant, une telle initialisation mettra le contenu du tableau à des valeurs par défaut :

  • boolean - le contenu du tableau sera initialisé à la valeur false ;
  • Nombres primitifs - le contenu du tableau sera initialisé à la valeur 0, 0F, 0L ou 0D suivant le type utilisé ;
  • Objets (y compris String, les classes wrapper des nombres et des sous-tableaux) - le contenu du tableau sera initialisé à la valeur null.


Il est également possible d'initialiser un tableau en donnant directement son contenu par des constantes ou des variables. Par exemple :

Code Java : Sélectionner tout
int[] tableauEntier = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; // Le tableau contiendra 10 éléments.

Ou :

Code Java : Sélectionner tout
int[] tableauEntier = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; // Le tableau contiendra 10 éléments.

Mis à jour le 2 juin 2015 bouye

Pour savoir si un objet est un tableau, il suffit de faire :

Code Java : Sélectionner tout
boolean estUnTableau = monObjet.getClass().isArray();

Mis à jour le 1er mars 2003 Clement Cunin

Pour accéder aux éléments d'un tableau, vous devez utiliser la syntaxe <nom du tableau>[<index de la valeur>] où l'index de la valeur est un entier positif ou strictement inférieur à la taille du tableau. Cette valeur peut être une constante ou le contenu d'une variable. L'objet retourné est du même type que le contenu du tableau.

De plus, en Java, la première cellule du tableau est toujours à l'index 0. Ainsi, un tableau de taille N sera indexable par la plage d'indices [0, N-1].

Par exemple :

Code Java : Sélectionner tout
1
2
3
int[] tableauEntier = {1 , 2 , 3, 4, 5, 6, 7, 8, 9, 10}; 
int valeur = tableauEntier[2]; // Récupère le 3e élément du tableau (index 2). 
tableauEntier[0] = 5; // Modifie la valeur du 1er élément du tableau (index 0).

Note : un tableau vide (initialisé avec la taille 0) ne contient aucun élément.

Avertissement : en Java, les accès aux données d'un tableau sont sécurisés. Si jamais vous tentez d’accéder au contenu du tableau en utilisant un index négatif ou supérieur ou égal à la taille du tableau, votre code générera une exception de type java.lang.ArrayIndexOutOfBoundsException.

Mis à jour le 5 juin 2015 bouye

Chaque tableau, qu'il contienne des primitifs ou des références vers des objets dispose d'un membre length qui contient la taille du tableau sous forme d'une valeur entière positive ou nulle. Ce membre a le modificateur final et n'est donc pas modifiable.

Ainsi, il est possible de faire :

Code Java : Sélectionner tout
1
2
int[] tableau = {1, 2, 3}; 
System.out.println(tableau.length); // Imprime 3 sur la console.

Mis à jour le 2 juin 2015 bouye

Il est impossible de changer la taille d'un tableau : la taille d'un tableau est fixe et ne peut pas être modifiée une fois que le tableau a été instancié.

Vous devez donc allouer un nouveau tableau à la taille appropriée et recopier le contenu de l'ancien tableau dans le nouveau. La méthode publique statique arraycopy() de la classe java.lang.System peut être utilisée à cet effet. Par exemple :

Code Java : Sélectionner tout
1
2
3
4
5
public int[] doubleLaTaille(final int[] source) { 
    final int[] result = new int[source.length * 2];  
    System.arraycopy(source, 0, result, 0, source.length); // Recopie le contenu de la source au début du résultat. 
    return result; 
}

La création d'un nouveau tableau est une opération coûteuse en termes de performances, si vous devez utiliser une structure de données dont la taille change souvent, il est fortement conseillé d'utiliser une liste.

Mis à jour le 2 juin 2015 bouye Clement Cunin

Dans les spécifications du langage Java, il est indiqué que, pour indexer un élément dans un tableau, il faut utiliser une valeur entière positive ou nulle.

En théorie, cela implique donc que le tableau 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 un tableau 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. Toute tentative d'allouer une taille supérieure à cette limite se soldera par une erreur de type java.lang.OutOfMemoryError contenant le message « Requested array size exceeds VM limit ». Même si la valeur est dans la limite supportée, une erreur java.lang.OutOfMemoryError contenant le message « Java heap space » peut être générée si la JVM échoue à allouer assez de mémoire pour créer un tel tableau en fonction du type des données stockées dans le tableau.

Code Java : Sélectionner tout
1
2
3
4
5
6
7
8
 // Un tableau de N bytes consomme N octets en mémoire. 
final byte[] test = new byte[Integer.MAX_VALUE]; // Échoue avec java.lang.OutOfMemoryError: Requested array size exceeds VM limit 
final byte[] test = new byte[Integer.MAX_VALUE-1]; // Échoue avec java.lang.OutOfMemoryError: Requested array size exceeds VM limit 
final byte[] test = new byte[Integer.MAX_VALUE-2]; // Fonctionne, 
// Un tableau de N int consomme 4 * N octets en mémoire. 
final int[] test = new int[Integer.MAX_VALUE]; // Échoue avec java.lang.OutOfMemoryError: Requested array size exceeds VM limit 
final int[] test = new int[Integer.MAX_VALUE-1]; // Échoue avec java.lang.OutOfMemoryError: Requested array size exceeds VM limit 
final int[] test = new int[Integer.MAX_VALUE-2]; // Échoue avec java.lang.OutOfMemoryError: Java heap space

Mis à jour le 2 juin 2015 bouye

Il existe de très nombreuses manières de parcourir tous les éléments d'un tableau. Nous allons en aborder quelques-unes des plus courantes :

Boucle for ou while
Nous pouvons effectuer le parcours à l'ancienne, avec une boucle for traditionnelle, par exemple :

Code Java : Sélectionner tout
1
2
3
4
5
int[] tab = new int[50] 
[...] 
for (int index = 0; index < tab.length; index++) { 
    System.out.println(tab[index]); 
}

Ou une boucle while :

Code Java : Sélectionner tout
1
2
3
4
5
6
7
int[] tab = new int[50] 
[...] 
int index = 0; 
while (index < tab.length) { 
    System.out.println(tab[index]); 
    index++; 
}

Boucle for étendu
Le JDK 5.0 apporte une construction de boucle performante qui permet de parcourir tous les éléments d'un tableau, ou d'un objet implémentant l'interface Iterable (ArrayList, etc.), sans se préoccuper de l'indice.

Code Java : Sélectionner tout
1
2
3
4
5
int[] tab = new int[50] 
[...] 
for (int n : tab) { 
    System.out.println(n); 
}

Streams
Le JDK 8 permet d'utiliser des flux sur des tableaux. Par exemple pour itérer sur l'index des valeurs :

Code Java : Sélectionner tout
1
2
3
4
int[] tab = new int[50] 
[...] 
IntStream.range(0, tab.length) 
    .forEach(index -> System.out.println(tab[index]));

Ou encore pour itérer sur les valeurs elles-mêmes :

Code Java : Sélectionner tout
1
2
3
4
int[] tab = new int[50]; 
[...] 
Arrays.stream(tab) 
    .forEach(System.out::println);

Mis à jour le 15 juin 2015 bigboomshakala bouye

Java ne supporte pas les tableaux multidimensionnels en tant que bloc mémoire unifié comme peuvent le faire d'autres langages. Il reste cependant possible de créer des tableaux de tableaux qui peuvent jouer un rôle similaire pour simuler des tableaux à dimensions multiples.

Pour indiquer que votre variable contient plus d'une seule dimension, il suffit de rajouter dans sa déclaration de type autant de [] qu'il y a de dimensions supplémentaires. Par exemple :

Code Java : Sélectionner tout
1
2
int[][] matriceEntiere2D; 
String[][][] matriceChaine3D;

En ce qui concerne l'initialisation, il est possible d'initialiser les dimensions séparément en commençant par les dimensions les plus à gauche :

Code Java : Sélectionner tout
1
2
int[][] matriceEntiere2D = new int[10][]; 
int[][] matriceEntiere2D = new int[][10]; // Erreur.

Ici, les sous-tableaux sont à la valeur null, car ils n'ont pas été alloués. Par exemple :

Code Java : Sélectionner tout
1
2
System.out.println(matriceEntiere2D[5])); // Imprime null. 
System.out.println(matriceEntiere2D[5][3])); // génère une NullPointerException.

Il faudra donc songer à les initialiser :

Code Java : Sélectionner tout
1
2
3
4
int[][] matriceEntiere2D = new int[10][]; 
for (int i = 0 ; i < 10 ; i++) { 
    matriceEntiere2D[i] = new int[10]; // Initialisation des sous-tableaux. 
}

Il est également possible d'initialiser toutes les dimensions en une seule fois.

Code Java : Sélectionner tout
int[][] matriceEntiere2D = new int[10][10];

Dans ce cas tous les sous-tableaux sont automatiquement alloués et ils seront tous de la même taille.

Dans les deux cas, les valeurs contenues dans chaque sous-tableau seront alors initialisées avec les valeurs par défaut habituelles (ici 0 puisque que nous manipulons des int).

Il est également possible d'initialiser directement le contenu des tableaux avec des constantes ou des variables. Par exemple :

Code Java : Sélectionner tout
String[][] matriceChaine2D = {{"Foo", "Fii"}, {"Faa", "Fuu"}};

Avertissement : gardez à l'esprit que, quand vous manipulez des tableaux de tableaux de ... de tableaux, rien de garantit que tous les sous-tableaux ont été correctement initialisés ou même qu'ils ont tous la même taille.

Pour accéder au contenu d'un tableau de tableaux, il suffit de rajouter autant de [<index de la valeur>] qu'il y a de dimensions supplémentaires et d'utiliser des valeurs d'indices légales pour la dimension de chaque sous-tableau qui est accédé. Il est également possible d’accéder ainsi aux divers sous-tableaux. Par exemple :

Code Java : Sélectionner tout
1
2
3
4
5
int[][] matriceEntier2D = new int[10][10]; 
int valeur = matriceEntier2D[5][7]; // Vaut 0. 
int[] vecteur = matriceEntier2D[8]; // Vaut [0,0,0,0,0,0,0,0,0,0]. 
matriceEntier2D[2][1] = 8; 
matriceEntier2D[1][6] = null;

Mis à jour le 2 juin 2015 bouye

Cette propriété n'est pas directement accessible, mais la fonction suivante permet de la calculer rapidement. On se base sur le fait qu'un tableau à plusieurs dimensions est en fait un tableau de tableaux.

Code Java : Sélectionner tout
1
2
3
4
5
6
7
8
9
public static int getNbDimension(Object monTableau) { 
    int dim=0; 
    Class cls = monTableau.getClass(); 
    while( cls.isArray()) { 
        cls = cls.getComponentType(); 
        dim++; 
    }  
    return( dim ); 
}

Mis à jour le 1er mars 2003 Clement Cunin

Le code suivant permet de parcourir un tableau à deux dimensions d'entiers et de les afficher :

Code Java : Sélectionner tout
1
2
3
4
5
6
int tab[][] = { {1, 2, 3}, {7, 8, 9} };  
for(int ligne[] : tab) { 
    for(int element : ligne) { 
        System.out.println("Item : " + element); 
    } 
}

Mis à jour le 12 octobre 2015 La rédaction Java

Pour trier le contenu d'un tableau, vous devez invoquer une des variantes de la méthode sort() de la classe utilitaire java.util.Arrays :

Code Java : Sélectionner tout
1
2
3
4
5
6
7
8
int[] unTableauDEntiers = [...] 
Arrays.sort(unTableauDEntiers); 
  
float[] unTableauDeFlottants= [...] 
Arrays.sort(unTableauDeFlottants); 
  
Voiture[] unTableauDeVoitures = [...] 
Arrays.sort(unTableauDeVoitures);

Par défaut, c'est l'ordre naturel des objets qui sera utilisé. Il est cependant possible de fournir un Comparator qui se chargera de faire le tri. Prenons, par exemple, un tableau contenant des voitures. Nous allons trier celui-ci en fonction de la puissance des véhicules :

Code Java : Sélectionner tout
1
2
Comparator<Voiture> comparateurDePuissance = [...] // Compare le nombre de chevaux au lieu du nom de la voiture. 
Arrays.sort(unTableauDeVoitures, comparateurDePuissance );

La méthode sort() effectue un tri rapide par double-pivot d’après l'algorithme de Vladimir Yaroslavskiy, Jon Bentley, et Joshua Bloch.

Depuis le JDK 8, il est également possible d'invoquer une des variantes de la méthode parallelSort() de la classe java.util.Arrays qui exécutera le tri en parallèle sur des sous-sections du tableau en utilisant plusieurs threads.

Mis à jour le 15 juin 2015 bouye

Contrairement à ce qu'on pourrait penser, il est possible de créer des instances de tableaux génériques. Il suffit pour cela d'invoquer une des variantes de la méthode publique statique newInstance() de la classe java.lang.reflect.Array. La première version de la méthode permet de créer un tableau classique à une dimension, tandis que la seconde version permet de spécifier de multiples dimensions. Dans les deux cas, il faut cependant détenir une référence vers la classe que nous désirons stocker dans le tableau.

Ainsi il est possible de faire :

Code Java : Sélectionner tout
String[] tableau = (String[])Array.newInstance(String.class, 100);

Ou dans un environnement qui manipule des génériques sans connaitre la valeur réelle du type T :

Code Java : Sélectionner tout
T[] tableau = (T[])Array.newInstance(uneValeurDeTypeT.getClass(), 100);

Mis à jour le 2 juin 2015 bouye

Le compilateur interdit toute création de tableaux de type paramétré, ainsi la ligne suivante provoquera irrémédiablement une erreur :

Code java : Sélectionner tout
List<String> stringListArray[] = new List<String>[100];

Ce problème vient du fait que les tableaux et les Generics ont une approche totalement opposée de la vérification des types.

Avec les tableaux, la quasi-totalité des vérifications sont effectuées pendant l'exécution, et la plupart des opérations sur les tableaux peuvent générer des ClassCastException selon le type réel du tableau et le type réel de l'élément qu'on lui affecte.

À l'inverse, les Generics sont sécurisés à la compilation. C'est-à-dire que c'est le compilateur qui se charge de vérifier la cohérence de l'ensemble pendant la compilation, et qui garantit l'absence d'exception pendant l'exécution.

Du fait de leurs fortes oppositions et de l'héritage particulier des tableaux, l'utilisation de tableaux Generics peut aboutir à des situations complètement fausses et générer des exceptions inattendues.

Ainsi, si la création de tableaux Generics était possible, il serait relativement simple de passer outre la protection des Generics sans warning ni erreur :

Code java : Sélectionner tout
1
2
3
4
5
List<String>[] stringListArray = new List<String>[100]; // ERREUR 
  
Object[] simpleArray = stringListArray; 
  
simpleArray[0] = new ArrayList<Number>(); // OK ?!?!?

Le pire c'est que ce code ne générerait même pas d'exception lors de son exécution. Au contraire l'exécution serait reportée lors de l'utilisation des données du tableau alors qu'il devrait s'agir d'un code sécurisé...

Bref, l'utilisation de tableaux Generics est loin d'assurer la sécurité de code promise par les Generics, et le compilateur interdit donc leur création.

Il existe pourtant une alternative.

La meilleure solution serait d'utiliser l'API de Collection, et donc une List à la place du tableau. En effet dans le cas de figure décrit ci-dessus, l'utilisation des Generics permettrait d'être averti du problème via un warning :

Code java : Sélectionner tout
1
2
3
4
5
List<List<String>> stringListList = new ArrayList<List<String>>(); 
  
List simpleList = stringListList; 
  
simpleList.add( new ArrayList<Number>() ); // Warning unchecked

La seconde solution, à n'utiliser que si l'utilisation du tableau est vraiment une nécessité, consiste à créer un tableau non Generics et à ignorer le warning reçu :

Code java : Sélectionner tout
1
2
@SuppressWarnings("unchecked") 
List<String>[] stringListArray = new List[100];

Mais bien entendu cela ne corrige en rien le problème des tableaux Generics…

Mis à jour le 25 août 2007 adiGuba

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 ça


Réponse à la question

Liens sous la question
précédent sommaire suivant
 

Les 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 © 2016 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.

 
Responsables bénévoles de la rubrique Java : Mickael Baron - Robin56 -