Javaでもラムダ式やStream APIなど比較的モダンな機能が取り入れられ、処理結果を2つ以上の値として返したい場合が増えてきています。
その方法として一つとして思いつくのが、他言語ではよく用意されているTupleです。
ところが、Javaには標準APIとしてTupleが用意されているないため、ちょっと調べたときのメモです。
Tupleとは
タプルとは、順序付けられた複数の要素で構成される組。もとは数学の概念だが、いくつかのプログラミング言語にはタプルという名称のデータ型が用意されている。
タプル型の仕様は言語によって異なるが、複数の異なる型のデータやオブジェクトなどを格納でき、配列のように各要素に通し番号(添字)が割り振られ、これによって要素を識別するようなデータ構造を表すことが多い。また、LISPなどの関数型言語では二分木の構造になっているデータ型をタプルという。
こちらはe-Wordsからの引用で、このあたりは言語や実装によっても違うのですが、ここで言うTupleは任意の数の要素、型をまとめる為のデータ構造です。
なぜ標準APIにTupleがないのか
Does Java SE 8 have Pairs or Tuples?
オラクルのJava、OpenJDK開発者の方の回答が参考になります。(一部抜粋と超要約)
Java SEでPair(Tuple)クラスを持つことが提案され、少なくとも1回は拒否されました。しかし、他のライブラリやアプリケーションで複数の実装が存在していて必要性は理解できます。ただし、Pairのような構造を標準APIとして提供すると、抽象化(クラス)を使わず、複雑なデータ構造をPairsやコレクションで表現したくなります。(
Pair<List<String>,List<Pair<String,List<Boolean>>>>
,Map<Double,List<Pair<QueryTuple,Map<StatType,Number>>>>
)
また、命名規則の問題やStream APIのような環境では、オブジェクト用のPairだけでなくプリミティブとの組み合わせのPairが必要になります。(ObjIntPair
,ObjLongPair
,ObjDoublePair
,IntObjPair
,IntIntPair
...)
などなど、将来的に実装の可能性はあるものの標準APIとして追加は決まっていないのが現状のようです。
ということで、他のパラダイムも含まれてるとは言え、オブジェクト指向言語のJavaでTupleが欲しくなったときは、適切な抽象化(クラス)をすることが現時点の方向性のようです。
ライブラリを使用する
Javaの方針とは言えそれでも欲しい場合もあると思います。
javafx.util.Pairを使うという方法もありますが、パッケージがjavafxだったり、Pairしか用意されていないなどもあり、外部のライブラリを使うのも手だと思います。
-
Commons Lang
PairとTripleを提供。多くのシステムやライブラリで採用されている為、意図的に追加しなくても使用できる場合もある。 -
javatuples
1〜10までのTupleを提供。基本的にTupleの為のライブラリのため余計なクラスの追加がない。 -
Reactor
2〜8までのTupleを提供。Spring 5からは標準のdependencyとして追加される。 -
Javaslang
0〜8までのTupleを提供 -
Functional Java
0〜8までのTuple(P)を提供 -
jOOλ
1〜16までのTupleを提供
比較的、関数指向の強いライブラリで提供されているケースが多いです。
注意が必要なのは、ライブラリによって、Tupleにもミュータブルなもとのイミュータブルなものがあると言うことです。
特にイミュータブルな性質のものは、Collectorのaccumulatorなどミュータブルな性質を想定しているAPIでは使用できないのできないので注意が必要です。
また、ライブラリによってはTuple以外のクラスも追加されるので安易に導入すると、管理が複雑になる可能性もあります。*1
実装する
ライブラリによる追加は楽な反面、課題*1も抱えているため機能性を求めない単純なTupleであれば、Lombokなどで簡単に実装してしまうという方法もあります。
@Data(staticConstructor = "of")
public class Pair<A, B> {
private final A left;
private final B right;
}
まとめ
ということで、JavaでTupleが欲しくなった場合には、
- クラスなどで表現できないか検討する
- 最小限の機能でよければ自作のTupleで代用する
- 本格的に使用するなら、ライブラリを検討する
と考えると良さそうです。