So geben Sie mehrere Werte von einer Java-Methode zurück

1. Übersicht

In diesem Tutorial lernen wir verschiedene Möglichkeiten kennen, um mehrere Werte von einer Java-Methode zurückzugeben.

Zuerst geben wir Arrays und Sammlungen zurück. Anschließend zeigen wir, wie Containerklassen für komplexe Daten verwendet werden und wie generische Tupelklassen erstellt werden.

Schließlich sehen wir Beispiele für die Verwendung von Bibliotheken von Drittanbietern, um mehrere Werte zurückzugeben.

2. Verwenden von Arrays

Arrays können verwendet werden, um sowohl primitive als auch Referenzdatentypen zurückzugeben .

Die folgende Methode getCoordinates gibt beispielsweise ein Array mit zwei Doppelwerten zurück :

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

Wenn wir ein Array mit verschiedenen Referenztypen zurückgeben möchten, können wir einen gemeinsamen übergeordneten Typ als Array-Typ verwenden :

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

Hier haben wir das Koordinatenarray vom Typ Number definiert, da es die gemeinsame Klasse zwischen Integer- und Double- Elementen ist.

3. Sammlungen verwenden

Mit generischen Java-Sammlungen können wir mehrere Werte eines gemeinsamen Typs zurückgeben .

Das Sammlungsframework verfügt über ein breites Spektrum an Klassen und Schnittstellen. In diesem Abschnitt beschränken wir uns jedoch auf die Listen- und Kartenschnittstellen .

3.1. Rückgabe von Werten ähnlichen Typs in einer Liste

Lassen Sie uns zunächst das vorherige Array-Beispiel mit List neu schreiben :

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

Wie Number [] enthält die List- Auflistung eine Folge von Elementen gemischten Typs, die alle denselben gemeinsamen Typ haben.

3.2. Rückgabe benannter Werte in einer Karte

Wenn wir jeden Eintrag in unserer Sammlung benennen möchten, kann stattdessen eine Karte verwendet werden:

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

Benutzer der getCoordinatesMap- Methode können die Schlüssel " longitude" oder " width " mit der Map # get- Methode verwenden, um den entsprechenden Wert abzurufen.

4. Verwenden von Containerklassen

Im Gegensatz zu Arrays und Sammlungen können Containerklassen (POJOs) mehrere Felder mit unterschiedlichen Datentypen umschließen .

Beispielsweise hat die folgende Coordinates- Klasse zwei verschiedene Datentypen, double und 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 }

Durch die Verwendung von Containerklassen wie Koordinaten können wir komplexe Datentypen mit aussagekräftigen Namen modellieren .

Der nächste Schritt besteht darin, eine Instanz von Koordinaten zu instanziieren und zurückzugeben :

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

Wir sollten beachten, dass empfohlen wird, Datenklassen wie Koordinaten unveränderlich zu machen . Auf diese Weise erstellen wir einfache, threadsichere und gemeinsam nutzbare Objekte.

5. Verwenden von Tupeln

Tupel speichern wie Container Felder unterschiedlicher Art. Sie unterscheiden sich jedoch darin, dass sie nicht anwendungsspezifisch sind .

Sie sind spezialisiert, wenn wir sie verwenden, um zu beschreiben, welche Typen sie verarbeiten sollen, sind jedoch Allzweckcontainer mit einer bestimmten Anzahl von Werten. Dies bedeutet, dass wir keinen benutzerdefinierten Code schreiben müssen, um sie zu haben, und wir können eine Bibliothek verwenden oder eine gemeinsame einzelne Implementierung erstellen.

Ein Tupel kann aus einer beliebigen Anzahl von Feldern sein und wird oft als Tuple n, wobei n die Anzahl der Felder ist. Zum Beispiel ist Tuple2 ein Zwei-Feld-Tupel, Tuple3 ist ein Drei-Feld-Tupel und so weiter.

Um die Bedeutung von Tupeln zu demonstrieren, betrachten wir das folgende Beispiel. Angenommen, wir möchten den Abstand zwischen einem Koordinatenpunkt und allen anderen Punkten in einer Liste ermitteln . Dann müssen wir das am weitesten entfernte Koordinatenobjekt zusammen mit der Entfernung zurückgeben.

Erstellen wir zunächst ein generisches Zwei-Felder-Tupel:

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

Als nächstes implementieren wir unsere Logik und verwenden eine Tuple2- Instanz, um die Ergebnisse zu verpacken:

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(); }

Die Verwendung von Tuple2 im vorherigen Beispiel hat uns daran gehindert , eine separate Containerklasse für die einmalige Verwendung mit dieser bestimmten Methode zu erstellen .

Tupel sollten wie Behälter unveränderlich sein . Darüber hinaus sollten wir Tupel aufgrund ihres allgemeinen Charakters eher intern als als Teil unserer öffentlichen API verwenden .

6. Bibliotheken von Drittanbietern

Einige Bibliotheken von Drittanbietern haben einen unveränderlichen Pair- oder Triple- Typ implementiert . Apache Commons Lang und Javatuples sind Paradebeispiele. Sobald wir diese Bibliotheken als Abhängigkeiten in unserer Anwendung haben, können wir die von den Bibliotheken bereitgestellten Pair- oder Triple- Typen direkt verwenden, anstatt sie selbst zu erstellen.

Schauen wir uns ein Beispiel an, in dem Apache Commons Lang verwendet wird, um ein Paar oder ein Triple- Objekt zurückzugeben.

Bevor wir weiter gehen, fügen wir die commons-lang3- Abhängigkeit in unsere pom.xml ein:

 org.apache.commons commons-lang3 3.9 

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

Wir haben auch erfahren, dass einige Bibliotheken von Drittanbietern Paar- und Dreifachtypen implementiert haben, und einige Beispiele aus der Apache Commons Lang-Bibliothek gesehen.

Wie üblich ist der Quellcode für diesen Artikel auf GitHub verfügbar.