1. Overview
1.概述
In this tutorial, we’ll learn different ways to return multiple values from a Java method.
在本教程中,我们将学习从一个Java方法返回多个值的不同方法。
First, we’ll return arrays and collections. Then we’ll demonstrate how to use container classes for complex data, and learn how to create generic tuple classes.
首先,我们将返回数组和集合。然后我们将演示如何为复杂的数据使用容器类,并学习如何创建通用元组类。
Finally, we’ll illustrate how to use third-party libraries to return multiple values.
最后,我们将说明如何使用第三方库来返回多个值。
2. Using Arrays
2.使用数组
Arrays can be used to return both primitive and reference data types.
数组可以用来返回原始数据类型和引用数据类型。
For example, the following getCoordinates method returns an array of two double values:
例如,下面的getCoordinates方法返回一个包含两个double值的数组。
double[] getCoordinatesDoubleArray() {
double[] coordinates = new double[2];
coordinates[0] = 10;
coordinates[1] = 12.5;
return coordinates;
}
If we want to return an array of different reference types, we can use a common parent type as the array’s type:
如果我们想返回一个不同引用类型的数组,我们可以使用一个共同的父类型作为数组的类型。
Number[] getCoordinatesNumberArray() {
Number[] coordinates = new Number[2];
coordinates[0] = 10; // Integer
coordinates[1] = 12.5; // Double
return coordinates;
}
Here we defined the coordinates array of type Number because it’s the common class between Integer and Double elements.
这里我们定义了coordinates数组的类型Number,因为它是Integer和Double元素之间的共同类。
3. Using Collections
3.使用收藏品
With generic Java collections, we can return multiple values of a common type.
通过通用的Java集合,我们可以返回一个共同类型的多个值。
The collections framework has a wide spectrum of classes and interfaces. However, in this section, we’ll limit our discussion to the List and Map interfaces.
集合框架拥有广泛的类和接口。然而,在本节中,我们将只讨论List和Map接口。
3.1. Returning Values of Similar Type in a List
3.1.在一个列表中返回相似类型的值
To start, let’s rewrite the previous array example using List<Number>:
首先,让我们用List<Number>重写前面的数组例子。
List<Number> getCoordinatesList() {
List<Number> coordinates = new ArrayList<>();
coordinates.add(10); // Integer
coordinates.add(12.5); // Double
return coordinates;
}
Like Number[], the List<Number> collection holds a sequence of mixed-type elements all of the same common type.
像Number[]一样,List<Number>集合持有一串混合类型的元素,这些元素都具有相同的公共类型。
3.2. Returning Named Values in a Map
3.2.返回地图中的命名值
If we want to name each entry in our collection, a Map can be used instead:
如果我们想给我们的集合中的每个条目命名,可以使用Map来代替。
Map<String, Number> getCoordinatesMap() {
Map<String, Number> coordinates = new HashMap<>();
coordinates.put("longitude", 10);
coordinates.put("latitude", 12.5);
return coordinates;
}
Users of the getCoordinatesMap method can use the “longitude” or “latitude” keys with the Map#get method to retrieve the corresponding value.
getCoordinatesMap方法的用户可以使用”longitude”或”latitude”键与Map#get方法来检索相应的值。
4. Using Container Classes
4.使用容器类
Unlike arrays and collections, container classes (POJOs) can wrap multiple fields with different data types.
与数组和集合不同,容器类(POJO)可以包裹不同数据类型的多个字段。
For instance, the following Coordinates class has two different data types, double and String:
例如,下面的Coordinates类有两种不同的数据类型:double和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
}
Using container classes like Coordinates enables us to model complex data types with meaningful names.
使用像Coordinates这样的容器类,使我们能够用有意义的名字来模拟复杂的数据类型。
The next step is to instantiate and return an instance of Coordinates:
下一步是实例化并返回一个Coordinates的实例。
Coordinates getCoordinates() {
double longitude = 10;
double latitude = 12.5;
String placeName = "home";
return new Coordinates(longitude, latitude, placeName);
}
It’s recommended that we make data classes like Coordinates immutable. By doing so, we create simple, thread-safe, sharable objects.
建议我们让像Coordinatesimmutable这样的数据类。通过这样做,我们可以创建简单的、线程安全的、可共享的对象。
5. Using Tuples
5.使用图元
Like containers, tuples store fields of different types. However, they differ in that they aren’t application-specific.
与容器一样,图元也存储不同类型的字段。然而,它们的不同之处在于,它们并不针对特定的应用程序。
They are specialized when we use them to describe which types we want them to handle, but can also act as a general purpose container for a certain number of values. This means we don’t need to write custom code to have them, and we can use a library, or create a common single implementation.
当我们用它们来描述我们希望它们处理哪些类型时,它们是专门的,但也可以作为一个通用的容器来处理一定数量的值。这意味着我们不需要写自定义代码来拥有它们,我们可以使用一个库,或者创建一个通用的单一实现。
A tuple can be of any number of fields, and is often called Tuplen, where n is the number of fields. For example, Tuple2 is a two-field tuple, Tuple3 is a three-field tuple, and so on.
一个元组可以有任意数量的字段,通常被称为Tuplen,其中n是字段的数量。例如,Tuple2是一个双字段元组,Tuple3是一个三字段元组,以此类推。
To demonstrate the importance of tuples, let’s consider the following example. Suppose that we want to find the distance between a Coordinates point and all the other points inside a List<Coordinates>. Then we need to return the most distant Coordinate object, along with the distance.
为了证明图元的重要性,让我们考虑下面的例子。假设我们想找到一个Coordinates点与List<Coordinates>内所有其他点之间的距离。那么我们需要返回最远的坐标对象,以及距离。
Let’s first create a generic two-fields tuple:
让我们首先创建一个通用的两字型元组。
public class Tuple2<K, V> {
private K first;
private V second;
public Tuple2(K first, V second){
this.first = first;
this.second = second;
}
// getters and setters
}
Next, let’s implement our logic and use a Tuple2<Coordinates, Double> instance to wrap the results:
接下来,让我们实现我们的逻辑,使用一个Tuple2<Coordinates, Double>实例来包装结果。
Tuple2<Coordinates, Double> getMostDistantPoint(List<Coordinates> 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();
}
Using Tuple2<Coordinates, Double> in the previous example saved us from creating a separate container class for one-time use with this particular method.
在前面的例子中使用Tuple2<Coordinates, Double>,使我们不必为一次性使用这个特定的方法而创建一个单独的容器类。
Like containers, tuples should be immutable. Additionally, due to their general-purpose nature, we should use tuples internally, rather than as part of our public API.
与容器一样,图元应该是不可变的。此外,由于其通用性,我们应该在内部使用图元,而不是作为我们公共API的一部分。
6. Third-Party Libraries
6.第三方图书馆
Some third-party libraries have implemented an immutable Pair or Triple type. Apache Commons Lang and javatuples are prime examples. Once we have those libraries as dependencies in our application, we can directly use the Pair or Triple types provided by the libraries, instead of creating them by ourselves.
一些第三方库已经实现了一个不可变的Pair或Triple类型。Apache Commons Lang和javatuples就是最好的例子。一旦我们将这些库作为我们应用程序的依赖项,我们就可以直接使用这些库所提供的Pair或Triple类型,而不是自己创建它们。
Let’s look at an example using Apache Commons Lang to return a Pair or a Triple object.
让我们看看一个使用Apache Commons Lang来返回Pair或Triple对象的例子。
First, let’s add the commons-lang3 dependency in our pom.xml:
首先,让我们在pom.xml中添加commons-lang3依赖性:。
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>
6.1. ImmutablePair From Apache Commons Lang
6.1.ImmutablePair From Apache Commons Lang
The ImmutablePair type from Apache Commons Lang is exactly what we want: an immutable type whose usage is straightforward.
来自Apache Commons Lang的ImmutablePair类型正是我们想要的:一个不可变的类型,其用法很简单。
It contains two fields, left and right. Let’s see how to make our getMostDistantPoint method return an object of the ImmutablePair type:
它包含两个字段,left和right。让我们看看如何使我们的getMostDistantPoint方法返回一个ImmutablePair类型的对象。
ImmutablePair<Coordinates, Double> getMostDistantPoint(
List<Coordinates> 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
6.2.ImmutableTriple 来自 Apache Commons Lang
The ImmutableTriple is pretty similar to the ImmutablePair. The only difference is, as its name suggests, an ImmutableTriple contains three fields: left, middle, and right.
ImmutableTriple与ImmutablePair相当相似。唯一的区别是,正如它的名字所暗示的,ImmutableTriple包含三个字段。left, middle, 和 right.。
Now let’s add a new method to our coordinates calculation to show how to use the ImmutableTriple type.
现在让我们为我们的坐标计算添加一个新的方法,以展示如何使用ImmutableTriple类型。
We’ll go through all points in a List<Coordinates> to find out the min, avg, and max distances to the given target point.
我们将通过List<Coordinates>中的所有点来找出到给定目标点的min、avg,和max距离。
Let’s see how we can return the three values with a single method using the ImmutableTriple class:
让我们看看如何使用ImmutableTriple类,用一个方法返回这三个值。
ImmutableTriple<Double, Double, Double> getMinAvgMaxTriple(
List<Coordinates> coordinatesList, Coordinates target) {
List<Double> 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
7.结语
In this article, we 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.
在这篇文章中,我们学习了如何使用数组、集合、容器和图元来从一个方法中返回多个值。我们可以在简单的情况下使用数组和集合,因为它们包裹着一个数据类型。
Conversely, containers and tuples are useful in creating complex types, with containers offering better readability.
相反,容器和图元在创建复杂类型时很有用,容器提供了更好的可读性。
We also learned that some third-party libraries have implemented pair and triple types, and illustrated some examples from the Apache Commons Lang library.
我们还了解到一些第三方库已经实现了对和三类型,并说明了Apache Commons Lang库的一些例子。
As usual, the source code for this article is available over on GitHub.
像往常一样,本文的源代码可以在GitHub上找到。