Come restituire più valori da un metodo Java

1. Panoramica

In questo tutorial impareremo diversi modi per restituire più valori da un metodo Java.

Per prima cosa, restituiremo array e raccolte. Quindi, mostreremo come utilizzare le classi contenitore per dati complessi e impareremo come creare classi di tupla generiche.

Infine, vedremo esempi di come utilizzare librerie di terze parti per restituire più valori.

2. Utilizzo di array

Gli array possono essere utilizzati per restituire tipi di dati primitivi e di riferimento .

Ad esempio, il seguente metodo getCoordinates restituisce un array di due valori double :

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

Se vogliamo restituire un array di diversi tipi di riferimento, possiamo usare un tipo genitore comune come tipo dell'array :

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

Qui abbiamo definito l' array di coordinate di tipo Number perché è la classe comune tra gli elementi Integer e Double .

3. Utilizzo delle raccolte

Con raccolte Java generiche, possiamo restituire più valori di un tipo comune .

Il framework delle collezioni ha un ampio spettro di classi e interfacce. Tuttavia, in questa sezione, limiteremo la nostra discussione alle interfacce List e Map .

3.1. Restituzione di valori di tipo simile in un elenco

Per cominciare, riscriviamo il precedente esempio di array usando List :

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

Come Number [] , la raccolta List contiene una sequenza di elementi di tipo misto tutti dello stesso tipo comune.

3.2. Restituzione di valori denominati in una mappa

Se desideriamo assegnare un nome a ciascuna voce della nostra raccolta, è possibile utilizzare una mappa :

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

Gli utenti del metodo getCoordinatesMap possono utilizzare i tasti " longitudine" o " latitudine" con il metodo Map # get per recuperare il valore corrispondente.

4. Utilizzo delle classi contenitore

A differenza degli array e delle raccolte, le classi contenitore (POJO) possono includere più campi con diversi tipi di dati .

Ad esempio, la seguente classe Coordinates ha due diversi tipi di dati, double e 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'utilizzo di classi contenitore come Coordinates ci consente di modellare tipi di dati complessi con nomi significativi .

Il passaggio successivo consiste nell'istanziare e restituire un'istanza di Coordinates :

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

Dobbiamo notare che è consigliabile rendere immutabili classi di dati come Coordinates . In questo modo, creiamo oggetti semplici, thread-safe e condivisibili.

5. Utilizzo delle tuple

Come i contenitori, le tuple memorizzano campi di diversi tipi. Tuttavia, differiscono in quanto non sono specifici dell'applicazione .

Sono specializzati quando li usiamo per descrivere quali tipi vogliamo che gestiscano, ma sono contenitori per scopi generali di un certo numero di valori. Ciò significa che non abbiamo bisogno di scrivere codice personalizzato per averli e possiamo usare una libreria o creare una singola implementazione comune.

Una tupla può essere composta da un numero qualsiasi di campi ed è spesso chiamata Tupla n, dove n è il numero di campi. Ad esempio, Tuple2 è una tupla a due campi, Tuple3 è una tupla a tre campi e così via.

Per dimostrare l'importanza delle tuple, consideriamo il seguente esempio. Supponiamo di voler trovare la distanza tra un punto di coordinate e tutti gli altri punti all'interno di una lista . Quindi, dobbiamo restituire quell'oggetto Coordinate più distante, insieme alla distanza.

Creiamo prima una tupla generica a due campi:

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

Successivamente, implementiamo la nostra logica e utilizziamo un'istanza Tuple2 per racchiudere i risultati:

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'utilizzo di Tuple2 nell'esempio precedente ci ha evitato di creare una classe contenitore separata da utilizzare una sola volta con questo particolare metodo .

Come i contenitori, le tuple dovrebbero essere immutabili . Inoltre, a causa della loro natura generica, dovremmo usare le tuple internamente piuttosto che come parte della nostra API pubblica .

6. Biblioteche di terze parti

Alcune librerie di terze parti hanno implementato un tipo Pair o Triple non modificabile . Apache Commons Lang e javatuples sono ottimi esempi. Una volta che abbiamo quelle librerie come dipendenze nella nostra applicazione, possiamo usare direttamente i tipi Pair o Triple forniti dalle librerie invece di crearle da soli.

Diamo un'occhiata a un esempio che utilizza Apache Commons Lang per restituire un oggetto Pair o Triple .

Prima di andare oltre, aggiungiamo la dipendenza commons-lang3 nel nostro pom.xml:

 org.apache.commons commons-lang3 3.9 

6.1. ImmutablePair di 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.

Abbiamo anche appreso che alcune librerie di terze parti hanno implementato tipi di coppia e triplo e abbiamo visto alcuni esempi dalla libreria Apache Commons Lang.

Come al solito, il codice sorgente di questo articolo è disponibile su GitHub.