Comment renvoyer plusieurs valeurs à partir d'une méthode Java

1. Vue d'ensemble

Dans ce didacticiel, nous allons apprendre différentes façons de renvoyer plusieurs valeurs à partir d'une méthode Java.

Tout d'abord, nous retournerons les tableaux et les collections. Ensuite, nous montrerons comment utiliser des classes de conteneur pour des données complexes et comment créer des classes de tuple génériques.

Enfin, nous verrons des exemples d'utilisation de bibliothèques tierces pour renvoyer plusieurs valeurs.

2. Utilisation de tableaux

Les tableaux peuvent être utilisés pour renvoyer des types de données primitifs et de référence .

Par exemple, la méthode getCoordinates suivante renvoie un tableau de deux valeurs doubles :

double[] getCoordinatesDoubleArray() { double[] coordinates = new double[2]; coordinates[0] = 10; coordinates[1] = 12.5; return coordinates; }

Si nous voulons retourner un tableau de différents types de référence, nous pouvons utiliser un type parent commun comme type de tableau :

Number[] getCoordinatesNumberArray() { Number[] coordinates = new Number[2]; coordinates[0] = 10; // Integer coordinates[1] = 12.5; // Double return coordinates; }

Ici, nous avons défini le tableau de coordonnées de type Number car c'est la classe commune entre les éléments Integer et Double .

3. Utilisation des collections

Avec les collections Java génériques, nous pouvons renvoyer plusieurs valeurs d'un type commun .

Le framework de collections a un large spectre de classes et d'interfaces. Cependant, dans cette section, nous limiterons notre discussion aux interfaces List et Map .

3.1. Renvoyer des valeurs de type similaire dans une liste

Pour commencer, réécrivons l'exemple de tableau précédent en utilisant List :

List getCoordinatesList() { List coordinates = new ArrayList(); coordinates.add(10); // Integer coordinates.add(12.5); // Double return coordinates; }

Comme Number [] , la collection List contient une séquence d'éléments de type mixte, tous du même type commun.

3.2. Renvoyer des valeurs nommées dans une carte

Si nous souhaitons nommer chaque entrée de notre collection, une carte peut être utilisée à la place:

Map getCoordinatesMap() { Map coordinates = new HashMap(); coordinates.put("longitude", 10); coordinates.put("latitude", 12.5); return coordinates; }

Les utilisateurs de la méthode getCoordinatesMap peuvent utiliser les touches « longitude» ou « latitude» avec la méthode Map # get pour récupérer la valeur correspondante.

4. Utilisation des classes de conteneurs

Contrairement aux tableaux et aux collections, les classes de conteneur (POJO) peuvent encapsuler plusieurs champs avec différents types de données .

Par exemple, la classe Coordinates suivante a deux types de données différents, double et String :

public class Coordinates { private double longitude; private double latitude; private String placeName; public Coordinates(double longitude, double latitude, String placeName) { this.longitude = longitude; this.latitude = latitude; this.placeName = placeName; } // getters and setters }

L'utilisation de classes de conteneurs comme Coordinates nous permet de modéliser des types de données complexes avec des noms significatifs .

L'étape suivante consiste à instancier et à renvoyer une instance de Coordinates :

Coordinates getCoordinates() { double longitude = 10; double latitude = 12.5; String placeName = "home"; return new Coordinates(longitude, latitude, placeName); }

Nous devons noter qu'il est recommandé de rendre les classes de données telles que Coordinates immuables . Ce faisant, nous créons des objets simples, thread-safe et partageables.

5. Utilisation de tuples

Comme les conteneurs, les tuples stockent des champs de différents types. Cependant, ils diffèrent en ce qu'ils ne sont pas spécifiques à une application .

Ils sont spécialisés lorsque nous les utilisons pour décrire les types que nous voulons qu'ils gèrent, mais sont des conteneurs à usage général d'un certain nombre de valeurs. Cela signifie que nous n'avons pas besoin d'écrire de code personnalisé pour les avoir et que nous pouvons utiliser une bibliothèque ou créer une implémentation unique commune.

Un tuple peut être composé de n'importe quel nombre de champs et est souvent appelé Tuple n, où n est le nombre de champs. Par exemple, Tuple2 est un tuple à deux champs, Tuple3 est un tuple à trois champs, et ainsi de suite.

Pour démontrer l'importance des tuples, considérons l'exemple suivant. Supposons que nous voulions trouver la distance entre un point de coordonnées et tous les autres points à l'intérieur d'une liste . Ensuite, nous devons renvoyer l'objet de coordonnées le plus éloigné, ainsi que la distance.

Commençons par créer un tuple générique à deux champs:

public class Tuple2 { private K first; private V second; public Tuple2(K first, V second){ this.first = first; this.second = second; } // getters and setters }

Ensuite, implémentons notre logique et utilisons une instance Tuple2 pour encapsuler les résultats:

Tuple2 getMostDistantPoint(List coordinatesList, Coordinates target) { return coordinatesList.stream() .map(coor -> new Tuple2(coor, coor.calculateDistance(target))) .max((d1, d2) -> Double.compare(d1.getSecond(), d2.getSecond())) // compare distances .get(); }

L'utilisation de Tuple2 dans l'exemple précédent nous a évité de créer une classe de conteneur distincte pour une utilisation unique avec cette méthode particulière .

Comme les conteneurs, les tuples doivent être immuables . De plus, en raison de leur nature générale, nous devrions utiliser des tuples en interne plutôt que dans le cadre de notre API publique .

6. Bibliothèques tierces

Certaines bibliothèques tierces ont implémenté un type Paire ou Triple immuable . Apache Commons Lang et javatuples sont des exemples de premier ordre. Une fois que nous avons ces bibliothèques comme dépendances dans notre application, nous pouvons directement utiliser les types Pair ou Triple fournis par les bibliothèques au lieu de les créer nous-mêmes.

Regardons un exemple utilisant Apache Commons Lang pour renvoyer un objet Pair ou Triple .

Avant d'aller plus loin, ajoutons la dépendance commons-lang3 dans notre pom.xml:

 org.apache.commons commons-lang3 3.9 

6.1. ImmutablePair d'Apache Commons Lang

The ImmutablePair type from Apache Commons Lang is exactly what we want: an immutable type whose usage is straightforward.

It contains two fields: left and right. Let's see how to make our getMostDistantPoint method return an object of the ImmutablePair type:

ImmutablePair getMostDistantPoint( List coordinatesList, Coordinates target) { return coordinatesList.stream() .map(coordinates -> ImmutablePair.of(coordinates, coordinates.calculateDistance(target))) .max(Comparator.comparingDouble(Pair::getRight)) .get(); }

6.2. ImmutableTriple from Apache Commons Lang

The ImmutableTriple is pretty similar to the ImmutablePair. The only difference is, as its name tells, an ImmutableTriple contains three fields: left, middle, and right.

Now, let's add a new method to our coordinates calculation to show how to use the ImmutableTriple type.

We're going to go through all points in a List to find out the min, avg, and max distances to the given target point.

Let's see how can we return the three values with a single method using the ImmutableTriple class:

ImmutableTriple getMinAvgMaxTriple( List coordinatesList, Coordinates target) { List distanceList = coordinatesList.stream() .map(coordinates -> coordinates.calculateDistance(target)) .collect(Collectors.toList()); Double minDistance = distanceList.stream().mapToDouble(Double::doubleValue).min().getAsDouble(); Double avgDistance = distanceList.stream().mapToDouble(Double::doubleValue).average().orElse(0.0D); Double maxDistance = distanceList.stream().mapToDouble(Double::doubleValue).max().getAsDouble(); return ImmutableTriple.of(minDistance, avgDistance, maxDistance); }

7. Conclusion

In this article, we've learned how to use arrays, collections, containers, and tuples to return multiple values from a method. We can use arrays and collections in simple cases since they wrap a single data type.

On the other hand, containers and tuples are useful in creating complex types, with containers offering better readability.

Nous avons également appris que certaines bibliothèques tierces avaient implémenté des types paires et triples et avons vu quelques exemples de la bibliothèque Apache Commons Lang.

Comme d'habitude, le code source de cet article est disponible à l'adresse over sur GitHub.