Opérations sur les baies en Java

1. Vue d'ensemble

Tout développeur Java sait qu'il n'est pas toujours facile de produire une solution propre et efficace avec des opérations de baie. Pourtant, ils sont un élément central de l'écosystème Java - et nous devrons les traiter à plusieurs reprises.

Pour cette raison, il est bon d'avoir une «feuille de triche» - un résumé des procédures les plus courantes pour nous aider à résoudre le casse-tête rapidement. Ce didacticiel vous sera utile dans ces situations.

2. Tableaux et classes d'assistance

Avant de continuer, il est utile de comprendre ce qu'est un tableau en Java et comment l'utiliser. Si c'est la première fois que vous travaillez avec lui en Java, nous vous suggérons de jeter un coup d'œil à cet article précédent où nous avons couvert tous les concepts de base.

Veuillez noter que les opérations de base prises en charge par une baie sont, d'une certaine manière, limitées. Il n'est pas rare de voir des algorithmes complexes pour exécuter des tâches relativement simples lorsqu'il s'agit de tableaux.

Pour cette raison, pour la plupart de nos opérations, nous utiliserons des classes et des méthodes d'assistance pour nous aider: la classe Arrays fournie par Java et celle d'Apache ArrayUtils .

Pour inclure ce dernier dans notre projet, nous devrons ajouter la dépendance Apache Commons:

 org.apache.commons commons-lang3 3.8.1 

Nous pouvons consulter la dernière version de cet artefact sur Maven Central.

3. Obtenez le premier et le dernier élément d'un tableau

C'est l'une des tâches les plus courantes et les plus simples grâce à la nature d'accès par index des tableaux.

Commençons par déclarer et initialiser un tableau int qui sera utilisé dans tous nos exemples (sauf indication contraire):

int[] array = new int[] { 3, 5, 2, 5, 14, 4 };

Sachant que le premier élément d'un tableau est associé à la valeur d'index 0 et qu'il a un attribut de longueur que nous pouvons utiliser, il est alors simple de comprendre comment nous pouvons obtenir ces deux éléments:

int firstItem = array[0]; int lastItem = array[array.length - 1];

4. Obtenir une valeur aléatoire à partir d'un tableau

En utilisant l' objet java.util.Random , nous pouvons facilement obtenir n'importe quelle valeur de notre tableau:

int anyValue = array[new Random().nextInt(array.length)];

5. Ajouter un nouvel élément à un tableau

Comme nous le savons, les tableaux contiennent une taille fixe de valeurs. Par conséquent, nous ne pouvons pas simplement ajouter un élément et dépasser cette limite.

Nous devrons commencer par déclarer un nouveau tableau plus grand et copier les éléments du tableau de base dans le second.

Heureusement, la classe Arrays fournit une méthode pratique pour répliquer les valeurs d'un tableau dans une nouvelle structure de taille différente:

int[] newArray = Arrays.copyOf(array, array.length + 1); newArray[newArray.length - 1] = newItem;

Facultativement, si la classe ArrayUtils est accessible dans notre projet, nous pouvons utiliser sa méthode add (ou son alternative addAll ) pour atteindre notre objectif dans une instruction sur une ligne:

int[] newArray = ArrayUtils.add(array, newItem);

Comme nous pouvons l'imaginer, cette méthode ne modifie pas l' objet de tableau d' origine ; nous devons affecter sa sortie à une nouvelle variable.

6. Insérez une valeur entre deux valeurs

En raison de son caractère de valeurs indexées, insérer un élément dans un tableau entre deux autres n'est pas un travail trivial.

Apache a considéré cela comme un scénario typique et a implémenté une méthode dans sa classe ArrayUtils pour simplifier la solution:

int[] largerArray = ArrayUtils.insert(2, array, 77);

Nous devons spécifier l'index dans lequel nous voulons insérer la valeur, et la sortie sera un nouveau tableau contenant un plus grand nombre d'éléments.

Le dernier argument est un argument variable (aka vararg ), nous pouvons donc insérer n'importe quel nombre d'éléments dans le tableau.

7. Comparez deux tableaux

Même si les tableaux sont des Object s et fournissent donc une méthode equals , ils utilisent l'implémentation par défaut de celui-ci, en s'appuyant uniquement sur l'égalité de référence.

Nous pouvons en tout cas invoquer les java.util.Arrays ' équivaut à la méthode pour vérifier si deux objets du tableau contiennent les mêmes valeurs:

boolean areEqual = Arrays.equals(array1, array2);

Note: this method is not effective for jagged arrays. The appropriate method to verify multi-dimensional structures' equality is the Arrays.deepEquals one.

8. Check if an Array Is Empty

This is an uncomplicated assignment having in mind that we can use the length attribute of arrays:

boolean isEmpty = array == null || array.length == 0;

Moreover, we also have a null-safe method in the ArrayUtils helper class that we can use:

boolean isEmpty = ArrayUtils.isEmpty(array);

This function still depends on the length of the data structure, which considers nulls and empty sub-arrays as valid values too, so we'll have to keep an eye on these edge cases:

// These are empty arrays Integer[] array1 = {}; Integer[] array2 = null; Integer[] array3 = new Integer[0]; // All these will NOT be considered empty Integer[] array3 = { null, null, null }; Integer[][] array4 = { {}, {}, {} }; Integer[] array5 = new Integer[3];

9. How to Shuffle the Elements of an Array

In order to shuffle the items in an array, we can use the ArrayUtil‘s feature:

ArrayUtils.shuffle(array);

This is a void method and operates on the actual values of the array.

10. Box and Unbox Arrays

We often come across methods that support only Object-based arrays.

Again the ArrayUtils helper class comes in handy to get a boxed version of our primitive array:

Integer[] list = ArrayUtils.toObject(array);

The inverse operation is also possible:

Integer[] objectArray = { 3, 5, 2, 5, 14, 4 }; int[] array = ArrayUtils.toPrimitive(objectArray);

11. Remove Duplicates from an Array

The easiest way of removing duplicates is by converting the array to a Set implementation.

As we may know, Collections use Generics and hence don't support primitive types.

For this reason, if we're not handling object-based arrays as in our example, we'll first need to box our values:

// Box Integer[] list = ArrayUtils.toObject(array); // Remove duplicates Set set = new HashSet(Arrays.asList(list)); // Create array and unbox return ArrayUtils.toPrimitive(set.toArray(new Integer[set.size()]));

Note: we can use other techniques to convert between an array and a Set object as well.

Also, if we need to preserve the order of our elements, we must use a different Set implementation, such as a LinkedHashSet.

12. How to Print an Array

Same as with the equals method, the array's toString function uses the default implementation provided by the Object class, which isn't very useful.

Both Arrays and ArrayUtils classes ship with their implementations to convert the data structures to a readable String.

Apart from the slightly different format they use, the most important distinction is how they treat multi-dimensional objects.

The Java Util's class provides two static methods we can use:

  • toString: doesn't work well with jagged arrays
  • deepToString: supports any Object-based arrays but doesn't compile with primitive array arguments

On the other hand, Apache's implementation offers a single toString method that works correctly in any case:

String arrayAsString = ArrayUtils.toString(array);

13. Map an Array to Another Type

It's often useful to apply operations on all array items, possibly converting them to another type of object.

With this objective in mind, we'll try to create a flexible helper method using Generics:

public static  U[] mapObjectArray( T[] array, Function function, Class targetClazz) { U[] newArray = (U[]) Array.newInstance(targetClazz, array.length); for (int i = 0; i < array.length; i++) { newArray[i] = function.apply(array[i]); } return newArray; }

If we don't use Java 8 in our project, we can discard the Function argument, and create a method for each mapping that we need to carry out.

We can now reuse our generic method for different operations. Let's create two test cases to illustrate this:

@Test public void whenMapArrayMultiplyingValues_thenReturnMultipliedArray() { Integer[] multipliedExpectedArray = new Integer[] { 6, 10, 4, 10, 28, 8 }; Integer[] output = MyHelperClass.mapObjectArray(array, value -> value * 2, Integer.class); assertThat(output).containsExactly(multipliedExpectedArray); } @Test public void whenMapDividingObjectArray_thenReturnMultipliedArray() { Double[] multipliedExpectedArray = new Double[] { 1.5, 2.5, 1.0, 2.5, 7.0, 2.0 }; Double[] output = MyHelperClass.mapObjectArray(array, value -> value / 2.0, Double.class); assertThat(output).containsExactly(multipliedExpectedArray); }

For primitive types, we'll have to box our values first.

As an alternative, we can turn to Java 8's Streams to carry out the mapping for us.

We'll need to transform the array into a Stream of Objects first. We can do so with the Arrays.stream method.

For example, if we want to map our int values to a custom String representation, we'll implement this:

String[] stringArray = Arrays.stream(array) .mapToObj(value -> String.format("Value: %s", value)) .toArray(String[]::new);

14. Filter Values in an Array

Filtering out values from a collection is a common task that we might have to perform in more than one occasion.

This is because at the time we create the array that will receive the values, we can't be sure of its final size. Therefore, we'll rely on the Streams approach again.

Imagine we want to remove all odd numbers from an array:

int[] evenArray = Arrays.stream(array) .filter(value -> value % 2 == 0) .toArray();

15. Other Common Array Operations

There are, of course, plenty of other array operations that we might need to perform.

Apart from the ones shown in this tutorial, we've extensively covered other operations in the dedicated posts:

  • Check if a Java Array Contains a Value
  • How to Copy an Array in Java
  • Removing the First Element of an Array
  • Finding the Min and Max in an Array with Java
  • Find Sum and Average in a Java Array
  • How to Invert an Array in Java
  • Joindre et fractionner des tableaux et des collections en Java
  • Combinaison de différents types de collections en Java
  • Rechercher toutes les paires de nombres dans un tableau qui s'additionnent à une somme donnée
  • Tri en Java
  • Calculateur de fréquence de mots efficace en Java
  • Tri par insertion en Java

16. Conclusion

Les tableaux sont l'une des fonctionnalités de base de Java, il est donc très important de comprendre comment ils fonctionnent et de savoir ce que nous pouvons et ne pouvons pas faire avec eux.

Dans ce didacticiel, nous avons appris comment gérer les opérations de tableau de manière appropriée dans des scénarios courants.

Comme toujours, le code source complet des exemples de travail est disponible sur notre référentiel Github.