本文翻译自:https://www.baeldung.com/java-method-return-multiple-values#:~:text=%20How%20to%20Return%20Multiple%20Values%20From%20a,multiple%20values%20of%20a…%204%20Conclusion%20More%20
文章目录
- 1.概览
- 2.使用数组
- 3.使用collections
- 3.1 用List返回相似类型的值
- 3.2 用Map返回命名值
- 4.使用容器类
- 5.使用元组
- 6.第三方库
- 6.1 Apache Commons Lang中的ImmutablePair
- 6.2 Apache Commons Lang中的ImmutableTriple
- 7.小结
1.概览
在本教程中,我们将学习从Java方法返回多个值的不同方法。
首先,我们将返回数组和集合。然后,我们将展示如何对复杂数据使用容器类,并学习如何创建泛型元组类。
最后,我们将看到如何使用第三方库返回多个值的示例。
2.使用数组
数组可用于返回基本数据类型和引用数据类型。
例如,下面的getCoordinates方法返回double数组:
double[] getCoordinatesDoubleArray() {
double[] coordinates = new double[2];
coordinates[0] = 10;
coordinates[1] = 12.5;
return coordinates;
}
如果要返回不同引用类型的数组,可以使用公共父类型作为数组的类型:
Number[] getCoordinatesNumberArray() {
Number[] coordinates = new Number[2];
coordinates[0] = 10; // Integer
coordinates[1] = 12.5; // Double
return coordinates;
}
这里我们定义了Number类型的coordinate数组,因为它是Integer和Double的共同父类。
3.使用collections
使用Java collections,我们可以返回一个类型的多个值。
collections框架具有丰富的类和接口。但是,在本节中,我们将仅讨论List和Map。
3.1 用List返回相似类型的值
首先,让我们使用List重写前面的数组示例:
List<Number> getCoordinatesList() {
List<Number> coordinates = new ArrayList<>();
coordinates.add(10); // Integer
coordinates.add(12.5); // Double
return coordinates;
}
与Number[]一样,List包含多个有公共父类的不同类型元素。
3.2 用Map返回命名值
如果要命名collections中的每个条目,可以使用Map:
Map<String, Number> getCoordinatesMap() {
Map<String, Number> coordinates = new HashMap<>();
coordinates.put("longitude", 10);
coordinates.put("latitude", 12.5);
return coordinates;
}
getCoordinateMap方法的调用者可以使用longitude或latitude键以及Map的get方法来获取相应的值。
4.使用容器类
与数组和集合不同,容器类(pojo)可以包装不同数据类型的多个字段。
例如,以下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
}
使用像Coordinates这样的容器类,我们可以用有意义的名称来建模复杂的数据类型。
下一步是实例化并返回Coordinates类的实例:
Coordinates getCoordinates() {
double longitude = 10;
double latitude = 12.5;
String placeName = "home";
return new Coordinates(longitude, latitude, placeName);
}
我们应该注意到,建议我们将coordinate等数据类设置为不可变的。通过这样做,我们可以创建简单的、线程安全的、可共享的对象。
5.使用元组
与容器一样,元组存储不同类型的字段。但是,它们的不同之处在于它们不是特定于应用程序的。
当我们使用它们来描述我们希望它们处理的类型时,它们才会被专门化。它们是包含一些值的通用容器。这意味着我们不需要编写定制代码就可以拥有它们,我们可以使用一个库,或者创建一个通用的单一实现。
元组可以是任意数量的字段,通常称为Tuplen,其中n是字段数。例如,Tuple2是两个字段的tuple,Tuple3是三个字段的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
}
接下来,让我们实现我们的逻辑,并使用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();
}
在上面的示例中,使用Tuple2<Coordinates,Double>可以避免我们创建一个单独的容器类(如若单独创建,则只能在这个方法中用一次。)
像容器一样,元组应该是不可变的。此外,由于元组的通用性,我们应该在内部使用元组,而不是将其作为公共API的一部分。
6.第三方库
一些第三方库实现了不可变的Pair或Triple类型。apache commons Lang和java tuples是主要的例子。一旦我们在应用程序中将这些库作为依赖项,我们就可以直接使用库提供的Pair或Triple类型,而不用自己创建。
让我们看一个使用apache commons Lang返回Pair或Triple对象的示例。
在进一步讨论之前,让我们在pom.xml文件:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.11</version>
</dependency>
6.1 Apache Commons Lang中的ImmutablePair
apache commons Lang中的ImmutablePair类型正是我们想要的:一种用法简单的不可变类型。
它包含两个字段: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 Apache Commons Lang中的ImmutableTriple
ImmutableTriple与ImmutablePair非常相似。唯一的区别是,正如其名称所示,ImmutableTriple包含三个字段:left、middle和right。
现在,让我们在坐标计算中添加一个新方法来演示如何使用ImmutableTriple类型。
我们将遍历列表中的所有点,找出到给定目标点的最小、平均和最大距离。
让我们看看如何使用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.小结
在本文中,我们学习了如何使用数组、collections、容器类和元组从一个方法返回多个值。我们可以在简单的情况下使用数组和collections,因为它们包装了单个数据类型。
另一方面,容器类和元组在创建复杂类型时很有用,容器类提供了更好的可读性。
我们还了解到,一些第三方库已经实现了pair和triple类型,并看到了apache commons Lang库中的一些示例。
与往常一样,本文的源代码可以在GitHub上找到。