Comment copier un tableau en Java

Comment copier un tableau en Java

1. Overview

Dans cet article rapide, nous aborderons différentes méthodes de copie de tableaux en Java. La copie de tableau peut sembler une tâche triviale, mais elle peut entraîner des résultats inattendus et des comportements de programme si elle n'est pas effectuée soigneusement.

2. La classeSystem

Commençons par la bibliothèque Java principale -System.arrayCopy(); ceci copie un tableau d'un tableau source vers un tableau de destination, en commençant l'action de copie de la position source vers la position cible jusqu'à la longueur spécifiée.

Le nombre d'éléments copiés dans le tableau cible est égal à la longueur spécifiée. Il fournit un moyen simple de copier une sous-séquence d'un tableau sur un autre.

Si l'un des arguments du tableau estnull,, il renvoie unNullPointerException et si l'un des arguments entiers est négatif ou hors de portée, il renvoie unIndexOutOfBoundException.

Jetons un œil à un exemple pour copier un tableau complet dans un autre en utilisant la classejava.util.System:

int[] array = {23, 43, 55};
int[] copiedArray = new int[3];

System.arraycopy(array, 0, copiedArray, 0, 3);

Les arguments de cette méthode sont; un tableau source, la position de départ à partir du tableau source, un tableau de destination, la position de départ dans le tableau de destination et le nombre d'éléments à copier.

Jetons un coup d'œil à un autre exemple qui montre la copie d'une sous-séquence d'un tableau source vers une destination:

int[] array = {23, 43, 55, 12, 65, 88, 92};
int[] copiedArray = new int[3];

System.arraycopy(array, 2, copiedArray, 0, 3);
assertTrue(3 == copiedArray.length);
assertTrue(copiedArray[0] == array[2]);
assertTrue(copiedArray[1] == array[3]);
assertTrue(copiedArray[2] == array[4]);

3. La classeArrays

La classeArrays propose également plusieurs méthodes surchargées pour copier un tableau dans un autre. En interne, il utilise la même approche fournie par la classeSystem que nous avons vue précédemment. Il fournit principalement deux méthodes,copyOf(…) etcopyRangeOf(…).

Jetons un coup d'œil auxcopyOf premiers:

int[] array = {23, 43, 55, 12};
int newLength = array.length;

int[] copiedArray = Arrays.copyOf(array, newLength);

Il est important de noter que la classeArrays utiliseMath.min(…) pour sélectionner le minimum de la longueur du tableau source et la valeur du nouveau paramètre de longueur pour déterminer la taille du tableau résultant.

Arrays.copyOfRange() prend 2 paramètres, «from' et«to' en plus du paramètre du tableau source. Le tableau résultant inclut l’index ‘from' mais l’index‘to' est exclu. Voyons un exemple:

int[] array = {23, 43, 55, 12, 65, 88, 92};

int[] copiedArray = Arrays.copyOfRange(array, 1, 4);
assertTrue(3 == copiedArray.length);
assertTrue(copiedArray[0] == array[1]);
assertTrue(copiedArray[1] == array[2]);
assertTrue(copiedArray[2] == array[3]);

Ces deux méthodesdo a shallow copy d'objets si elles sont appliquées à un tableau de types d'objets non primitifs. Voyons un exemple de cas de test:

Employee[] copiedArray = Arrays.copyOf(employees, employees.length);

employees[0].setName(employees[0].getName() + "_Changed");

assertArrayEquals(copiedArray, array);

Comme le résultat est une copie superficielle, une modification du nom d'employé d'un élément du tableau d'origine a provoqué la modification du tableau de copie.

Et ainsi - si nous voulons faire une copie complète de types non primitifs - nous pouvons utiliser les autres options décrites dans les sections suivantes.

4. Copie de tableau avecObject.clone()

Object.clone() est hérité de la classeObject dans un tableau.

Copions d'abord un tableau de types primitifs à l'aide de la méthode de clonage:

int[] array = {23, 43, 55, 12};

int[] copiedArray = array.clone();

Et une preuve que cela fonctionne:

assertArrayEquals(copiedArray, array);
array[0] = 9;

assertTrue(copiedArray[0] != array[0]);

L'exemple ci-dessus montre qui ont le même contenu après le clonage mais qui contiennent des références différentes, de sorte que toute modification de l'une d'elles n'affectera pas l'autre.

D'autre part, si nous clonons un tableau de types non primitifs en utilisant la même méthode, les résultats seront différents.

Il créea shallow copy des éléments de tableau de type non primitif, même si la classe de l’objet inclus implémente l’interfaceCloneable et remplace la méthodeclone() de la classeObject.

Prenons un exemple:

public class Address implements Cloneable {
    // ...

    @Override
    protected Object clone() throws CloneNotSupportedException {
         super.clone();
         Address address = new Address();
         address.setCity(this.city);

         return address;
    }
}

Nous pouvons tester notre implémentation en créant un nouveau tableau d'adresses et en invoquant notre méthodeclone():

Address[] addresses = createAddressArray();
Address[] copiedArray = addresses.clone();
addresses[0].setCity(addresses[0].getCity() + "_Changed");
assertArrayEquals(copiedArray, addresses);

Cet exemple montre que tout changement dans le tableau d'origine ou copié entraînerait le changement dans l'autre même lorsque les objets inclus sontCloneable.

5. Utilisation de l'APIStream

En fin de compte, nous pouvons également utiliser l’API Stream pour la copie de tableaux. Prenons un exemple:

String[] strArray = {"orange", "red", "green'"};
String[] copiedArray = Arrays.stream(strArray).toArray(String[]::new);

Pour les types non primitifs, il effectuera également une copie superficielle des objets. Pour en savoir plus surJava 8 Streams, vous pouvez démarrerhere.

6. Bibliothèques externes

Apache Commons 3 propose une classe utilitaire appeléeSerializationUtils qui fournit une méthodeclone(…). C'est très utile si nous devons faire une copie complète d'un tableau de types non primitifs. Il peut être téléchargé depuishere et sa dépendance Maven est:


    org.apache.commons
    commons-lang3
    3.5

Jetons un œil à un cas de test:

public class Employee implements Serializable {
    // fields
    // standard getters and setters
}

Employee[] employees = createEmployeesArray();
Employee[] copiedArray = SerializationUtils.clone(employees);
employees[0].setName(employees[0].getName() + "_Changed");
assertFalse(
  copiedArray[0].getName().equals(employees[0].getName()));

Cette classe requiert que chaque objet implémente l'interfaceSerializable. En termes de performances, il est plus lent que les méthodes de clonage écrites manuellement pour chacun des objets de notre graphe d'objets à copier.

7. Conclusion

Dans ce tutoriel, nous avons examiné les différentes options pour copier un tableau en Java.

La méthode à utiliser dépend principalement du scénario exact. Tant que nous utilisons un tableau de type primitif, nous pouvons utiliser l’une des méthodes proposées par les classesSystem etArrays. Il ne devrait y avoir aucune différence de performances.

Pour les types non primitifs, si nous avons besoin de faire une copie complète d'un tableau, nous pouvons soit utiliser lesSerializationUtils, soit ajouter explicitement des méthodes de clonage à nos classes.

Et comme toujours, les exemples présentés dans cet article sont disponibles surover on GitHub.