1. 概要

このチュートリアルでは、Javaメソッドから複数の値を返すさまざまな方法を学習します。

まず、配列とコレクションを返します。 次に、複雑なデータにコンテナクラスを使用する方法を示し、ジェネリックタプルクラスを作成する方法を学習します。

最後に、サードパーティのライブラリを使用して複数の値を返す方法の例を示します。

2. 配列の使用

配列を使用して、プリミティブデータ型と参照データ型の両方を返すことができます

たとえば、次の getCoordinates メソッドは、2つの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;
}

ここでは、Integer要素とDouble要素の間の共通クラスであるため、タイプNumbercoordinates配列を定義しました。

3. コレクションの使用

一般的なJavaコレクションを使用すると、共通タイプの複数の値を返すことができます。

コレクションフレームワークには、幅広いクラスとインターフェイスがあります。 ただし、このセクションでは、説明をListおよびMapインターフェイスに限定します。

3.1. リスト内の同様のタイプの戻り値

まず、前の配列の例を次のように書き直してみましょう。 リスト

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

お気に入り番号[] リストコレクションは、すべて同じ共通タイプの混合タイプ要素のシーケンスを保持します。

3.2. マップで名前付きの値を返す

コレクション内の各エントリに名前を付ける場合は、代わりにMapを使用できます。

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

getCoordinatesMap メソッドのユーザーは、「longitude」または「latitude」キーとMap#get メソッドを使用して、対応する価値。

4. コンテナクラスの使用

配列やコレクションとは異なり、コンテナクラス(POJO)は、異なるデータ型で複数のフィールドをラップできます。

たとえば、次の Coordinates クラスには、doubleStringの2つの異なるデータ型があります。

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

Coordinatesのようなデータクラスを不変にすることをお勧めします。 そうすることで、シンプルでスレッドセーフな共有可能なオブジェクトを作成します。

5. タプルの使用

コンテナーと同様に、タプルはさまざまなタイプのフィールドを格納します。 ただし、アプリケーション固有ではないという点で異なります

これらは、処理するタイプを記述するために使用する場合に特化されていますが、特定の数の値の汎用コンテナーです。 つまり、カスタムコードを記述してそれらを作成する必要はなく、ライブラリを使用することも、共通の単一の実装を作成することもできます。

タプルは任意の数のフィールドにすることができ、 Tuple nと呼ばれることがよくあります。ここで、nはフィールドの数です。 たとえば、Tuple2は2フィールドのタプル、Tuple3は3フィールドのタプルなどです。

タプルの重要性を示すために、次の例を考えてみましょう。 との間の距離を見つけたいと仮定しますコーディネートポイントおよび内部の他のすべてのポイントリスト 。 次に、その最も遠いCoordinateオブジェクトを距離とともに返す必要があります。

まず、一般的な2フィールドタプルを作成しましょう。

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
}

次に、ロジックを実装して、 タプル2 結果をラップするインスタンス:

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の使用前の例では、この特定のメソッドで1回だけ使用するための個別のコンテナクラスを作成する必要がありません。

コンテナと同様に、タプルは不変である必要があります。 さらに、その汎用性により、パブリックAPI の一部としてではなく、内部でタプルを使用する必要があります。

6. サードパーティのライブラリ

一部のサードパーティライブラリは、不変のPairまたはTripleタイプを実装しています。 Apache CommonsLangおよびjavatuplesが代表的な例です。 これらのライブラリをアプリケーションの依存関係として取得すると、ライブラリが提供するPairまたはTripleタイプを、自分で作成する代わりに直接使用できます。

ApacheCommonsLangを使用してPairまたはTripleオブジェクトを返す例を見てみましょう。

さらに先に進む前に、 commons-lang3依存関係をpom.xml:に追加しましょう。

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.12.0</version>
</dependency>

6.1. ApacheCommonsLangのImmutablePair

ApacheCommonsLangのImmutablePairタイプは、まさに私たちが望んでいるタイプです。使用法が簡単な不変タイプです。

leftrightの2つのフィールドが含まれています。 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. ApacheCommonsLangのImmutableTriple

ImmutableTriple は、ImmutablePairと非常によく似ています。 唯一の違いは、その名前が示すように、 ImmutableTriple には、 left middle、rightの3つのフィールドが含まれていることです。

次に、 ImmutableTriple タイプの使用方法を示すために、座標計算に新しいメソッドを追加しましょう。

のすべてのポイントを通過しますリスト見つけるために 平均、最大指定されたターゲットポイントまでの距離。

ImmutableTriple クラスを使用して、1つのメソッドで3つの値を返す方法を見てみましょう。

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. 結論

この記事では、配列、コレクション、コンテナー、およびタプルを使用して、メソッドから複数の値を返す方法を学習しました。 配列とコレクションは単一のデータ型をラップするため、単純なケースで使用できます。

一方、コンテナーとタプルは複雑なタイプを作成するのに役立ち、コンテナーは読みやすさを向上させます。

また、一部のサードパーティライブラリがペアタイプとトリプルタイプを実装していることを学び、ApacheCommonsLangライブラリからいくつかの例を見ました。

いつものように、この記事のソースコードはGitHubから入手できます。