4
4

More than 3 years have passed since last update.

Java のメソッドで複数の値を返す方法あれこれ (Generics, Record, Triple, Tuple, 標準ライブラリや外部ライブラリを使用)

Last updated at Posted at 2020-10-13

概要

  • Java のメソッドで複数の値を返す方法について、標準ライブラリや外部ライブラリを使用したサンプルコードを挙げる (3つの値を返すサンプルコード)

環境

  • Java 15 (AdoptOpenJDK 15+36)
  • Gradle 6.6.1
  • macOS Catalina

使用している外部ライブラリ

  • Kotlin Standard Library 1.4.10
  • Scala Standard Library 2.13.3
  • Apache Commons Lang 3.11
  • Functional Java 4.8.1
  • javatuples 1.2
  • jOOλ 0.9.14
  • Reactor Core 3.3.10
  • Vavr 0.10.3

外部ライブラリを使わない方法

標準ライブラリ java.lang.Object[]

Object の配列に値をセットして返す。
受け取った側はキャストが必要。

public class ArraySample {

  static Object[] getArray() {
    Object[] array = new Object[3];
    array[0] = "foo";
    array[1] = true;
    array[2] = 123456;
    return array;
  }

  public static void main(String[] args) {
    Object[] array = getArray();
    String  foo = (String) array[0];
    boolean bar = (boolean) array[1];
    int     baz = (int) array[2];
    System.out.println(foo);
    System.out.println(bar);
    System.out.println(baz);
  }
}

標準ライブラリ java.util.List

List の要素に値をセットして返す。
受け取った側はキャストが必要。

import java.util.ArrayList;
import java.util.List;

public class ListSample {

  static List<Object> getList() {
    ArrayList<Object> list = new ArrayList<>();
    list.add("foo");
    list.add(true);
    list.add(123456);
    return list;
  }

  public static void main(String[] args) {
    List<Object> list = getList();
    String  foo = (String) list.get(0);
    boolean bar = (boolean) list.get(1);
    int     baz = (int) list.get(2);
    System.out.println(foo);
    System.out.println(bar);
    System.out.println(baz);
  }
}

標準ライブラリ java.util.Map

Map の要素に値をセットして返す。
受け取った側はキャストが必要。

import java.util.HashMap;
import java.util.Map;

public class MapSample {

  static Map<String, Object> getMap() {
    HashMap<String, Object> map = new HashMap<>();
    map.put("foo", "foo");
    map.put("bar", true);
    map.put("baz", 123456);
    return map;
  }

  public static void main(String[] args) {
    Map<String, Object> map = getMap();
    String  foo = (String) map.get("foo");
    boolean bar = (boolean) map.get("bar");
    int     baz = (int) map.get("baz");
    System.out.println(foo);
    System.out.println(bar);
    System.out.println(baz);
  }
}

クラスを定義する

クラスを定義してフィールドに値をセットして返す。

public class ClassSample {

  static class MyClass {
    String foo;
    boolean bar;
    int baz;
  }

  static MyClass getMyClass() {
    MyClass cls = new MyClass();
    cls.foo = "foo";
    cls.bar = true;
    cls.baz = 123456;
    return cls;
  }

  public static void main(String[] args) {
    MyClass cls = getMyClass();
    String  foo = cls.foo;
    boolean bar = cls.bar;
    int     baz = cls.baz;
    System.out.println(foo);
    System.out.println(bar);
    System.out.println(baz);
  }
}

ジェネリクス化したクラスを定義する

ジェネリクス化したクラスを定義して、使用する際に型を指定する。
フィールドに値をセットして返す。

public class GenericsSample {

  static class ValuesGenerics<T1, T2, T3> {
    T1 foo;
    T2 bar;
    T3 baz;
  }

  static ValuesGenerics<String, Boolean, Integer> getGenerics() {
    ValuesGenerics<String, Boolean, Integer> generics = new ValuesGenerics<>();
    generics.foo = "foo";
    generics.bar = true;
    generics.baz = 123456;
    return generics;
  }

  public static void main(String[] args) {
    ValuesGenerics<String, Boolean, Integer> generics = getGenerics();
    String  foo = generics.foo;
    boolean bar = generics.bar;
    int     baz = generics.baz;
    System.out.println(foo);
    System.out.println(bar);
    System.out.println(baz);
  }
}

レコードを定義する

レコード (Java 16 から正式導入予定) を定義して使用する。

public class RecordSample {

  record ValuesRecord(String foo, boolean bar, int baz) {
  }

  static ValuesRecord getRecord() {
    return new ValuesRecord("foo", true, 123456);
  }

  public static void main(String[] args) {
    ValuesRecord record = getRecord();
    String  foo = record.foo;
    boolean bar = record.bar;
    int     baz = record.baz;
    System.out.println(foo);
    System.out.println(bar);
    System.out.println(baz);
  }
}

参考: JEP 384: Records (Second Preview)

外部ライブラリを使う方法

Kotlin Standard Library (kotlin.Triple)

Kotlin の標準ライブラリを Java から使用する。
Kotlin の標準ライブラリには、2つの値を扱う Pair と、3つの値を扱う Triple がある。

import kotlin.Triple;

public class KotlinSample {

  static Triple<String, Boolean, Integer> getTriple() {
    return new Triple<>("foo", true, 123456);
  }

  public static void main(String[] args) {
    Triple<String, Boolean, Integer> triple = getTriple();
    String  foo = triple.getFirst();
    boolean bar = triple.getSecond();
    int     baz = triple.getThird();
    System.out.println(foo);
    System.out.println(bar);
    System.out.println(baz);
  }
}

参考: Triple - Kotlin Programming Language

Scala Standard Library (scala.Tuple3)

Scala の標準ライブラリを Java から使用する。
Scala の標準ライブラリには、1つの値を扱う Tuple1 から、22個の値を扱う Tuple22 まである。

import scala.Tuple3;

public class ScalaSample {

  static Tuple3<String, Boolean, Integer> getTuple3() {
    return new Tuple3<>("foo", true, 123456);
  }

  public static void main(String[] args) {
    Tuple3<String, Boolean, Integer> tuple = getTuple3();
    String  foo = tuple._1();
    boolean bar = tuple._2();
    int     baz = tuple._3();
    System.out.println(foo);
    System.out.println(bar);
    System.out.println(baz);
  }
}

参考: Scala Standard Library 2.13.3 - scala.Tuple3

Apache Commons Lang (org.apache.commons.lang3.tuple.Triple)

Apache Commons Lang には、2つの値を扱う Pair と、3つの値を扱う Triple がある。

import org.apache.commons.lang3.tuple.Triple;

public class ApacheCommonsLangSample {

  static Triple<String, Boolean, Integer> getTriple() {
    return Triple.of("foo", true, 123456);
  }

  public static void main(String[] args) {
    Triple<String, Boolean, Integer> triple = getTriple();
    String  foo = triple.getLeft();
    boolean bar = triple.getMiddle();
    int     baz = triple.getRight();
    System.out.println(foo);
    System.out.println(bar);
    System.out.println(baz);
  }
}

参考: Triple (Apache Commons Lang 3.11 API)

Functional Java (fj.P3)

Functional Java には、1つの値を扱う P1 から、8個の値を扱う P8 まである。

import fj.P;
import fj.P3;

public class FunctionalJavaSample {

  static P3<String, Boolean, Integer> getP3() {
    return P.p("foo", true, 123456);
  }

  public static void main(String[] args) {
    P3<String, Boolean, Integer> p = getP3();
    String  foo = p._1();
    boolean bar = p._2();
    int     baz = p._3();
    System.out.println(foo);
    System.out.println(bar);
    System.out.println(baz);
  }
}

参考: P3 (core 4.8.1 API)

javatuples (org.javatuples.Triplet)

javatuples には、1つの値を扱う Unit から、10個の値を扱う Decade まである。

import org.javatuples.Triplet;

public class JavatuplesSample {

  static Triplet<String, Boolean, Integer> getTriplet() {
    return Triplet.with("foo", true, 123456);
  }

  public static void main(String[] args) {
    Triplet<String, Boolean, Integer> triplet = getTriplet();
    String  foo = triplet.getValue0();
    boolean bar = triplet.getValue1();
    int     baz = triplet.getValue2();
    System.out.println(foo);
    System.out.println(bar);
    System.out.println(baz);
  }
}

参考: Triplet (javatuples 1.2 API)

jOOλ (org.jooq.lambda.tuple.Tuple3)

jOOλ には、0個の値を扱う Tuple0 から、16個の値を扱う Tuple16 まである。

import org.jooq.lambda.tuple.Tuple;
import org.jooq.lambda.tuple.Tuple3;

public class JoolSample {

  static Tuple3<String, Boolean, Integer> getTuple3() {
    return Tuple.tuple("foo", true, 123456);
  }

  public static void main(String[] args) {
    Tuple3<String, Boolean, Integer> tuple = getTuple3();
    String  foo = tuple.v1();
    boolean bar = tuple.v2();
    int     baz = tuple.v3();
    System.out.println(foo);
    System.out.println(bar);
    System.out.println(baz);
  }
}

参考: Tuple3 (jOOL 0.9.14 API)

Reactor (reactor.util.function.Tuple3)

Reactor には、2個の値を扱う Tuple2 から、8個の値を扱う Tuple8 まである。

import reactor.util.function.Tuple3;
import reactor.util.function.Tuples;

public class ReactorSample {

  static Tuple3<String, Boolean, Integer> getTuple3() {
    return Tuples.of("foo", true, 123456);
  }

  public static void main(String[] args) {
    Tuple3<String, Boolean, Integer> tuple = getTuple3();
    String  foo = tuple.getT1();
    boolean bar = tuple.getT2();
    int     baz = tuple.getT3();
    System.out.println(foo);
    System.out.println(bar);
    System.out.println(baz);
  }
}

参考: Tuple3 (reactor-core 3.3.10.RELEASE)

Vavr (io.vavr.Tuple3)

Vavr には、0個の値を扱う Tuple0 から、8個の値を扱う Tuple8 まである。

import io.vavr.Tuple;
import io.vavr.Tuple3;

public class VavrSample {

  static Tuple3<String, Boolean, Integer> getTuple3() {
    return Tuple.of("foo", true, 123456);
  }

  public static void main(String[] args) {
    Tuple3<String, Boolean, Integer> tuple = getTuple3();
    String  foo = tuple._1();
    boolean bar = tuple._2();
    int     baz = tuple._3();
    System.out.println(foo);
    System.out.println(bar);
    System.out.println(baz);
  }
}

参考: Tuple3 (Vavr 0.10.3 API)

サンプルコード実行用ファイル

build.gradle

plugins {
  id 'java'
  id 'application'
}

repositories {
  mavenCentral()
}

dependencies {
  // 必要なライブラリ群
  implementation 'org.jetbrains.kotlin:kotlin-stdlib:1.4.10'
  implementation 'org.scala-lang:scala-library:2.13.3'
  implementation 'org.apache.commons:commons-lang3:3.11'
  implementation 'org.functionaljava:functionaljava:4.8.1'
  implementation 'org.javatuples:javatuples:1.2'
  implementation 'org.jooq:jool:0.9.14'
  implementation 'io.projectreactor:reactor-core:3.3.10.RELEASE'
  implementation 'io.vavr:vavr:0.10.3'
}

sourceCompatibility = JavaVersion.VERSION_15
mainClassName = "App"

tasks.withType(JavaCompile) {
  // Java 15 のプレビュー機能を使う
  options.compilerArgs += ['--enable-preview']
}

application {
  // Java 15 のプレビュー機能を使う
  applicationDefaultJvmArgs = ['--enable-preview']
}

サンプルコードまとめて実行用クラス

public class App {

  public static void main(String[] args) {
    ArraySample.main(args);
    ListSample.main(args);
    MapSample.main(args);
    ClassSample.main(args);
    GenericsSample.main(args);
    RecordSample.main(args);
    KotlinSample.main(args);
    ScalaSample.main(args);
    ApacheCommonsLangSample.main(args);
    FunctionalJavaSample.main(args);
    JavatuplesSample.main(args);
    JoolSample.main(args);
    ReactorSample.main(args);
    VavrSample.main(args);
  }
}

参考資料

4
4
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
4