Java の Pair について考える

### 背景
Java で Key と Value だけを持つデータが必要な場合は何を使いますか？Map でできないことはありません。が、あまりスマートなやり方でもありません。
Pair の実装が Java SE にない(わけではありませんが、あまり知られていません)ので、OSS を含めて調べてみました。

### AbstractMap.SimpleEntry
実は 1.6 から標準に Pair の機能を提供する API がありました。Entry の実装です。~~名前が長ったらしいですね。~~

#### インスタンス作成
new AbstractMap.SimpleEntry<K, V>(key, value)

#### キー・値の取り出し
Key は getKey() で、Value は getValue() で可能

#### 値の変更
setValue メソッドで Value のみ変更可能

#### 備考
AbstractMap には SimpleImmutableEntry というのもあります。こちらだと、setValue メソッドを実質無効にした、要素の変更が不可能な Entry を扱うことができます。setValue メソッドを呼び出すと UnsupportedOperationException が発生します。~~この実装はうれしいのでしょうか？~~

名前が長い件については、下記のようにラップしてやれば解決できます。

```java:Pair.java
 public class Pair<K, V> extends AbstractMap.SimpleEntry<K, V> {
    /** serialVersionUID. */
    private static final long serialVersionUID = 6411527075103472113L;

    public Pair(final K key, final V value) {
        super(key, value);
    }
 }
```

#### テストコード
1. [Pair (AbstractMap.SimpleEntry)](https://github.com/toastkidjp/pair_verification/blob/master/src/test/java/jp/toastkid/pair/java/util/PairTest.java)
2. [ImmutablePair (AbstractMap.SimpleImmutableEntry)](|https://github.com/toastkidjp/pair_verification/blob/master/src/test/java/jp/toastkid/pair/java/util/ImmutablePairTest.java)

### javafx.util.Pair
JavaFX 2.0 以降のライブラリに含まれている Pair の実装です。上記の SimpleEntry とほぼ同じ使い方が可能です。ただし値を入れ替えることはできません。

#### テストコード
[Pair](https://github.com/toastkidjp/pair_verification/blob/master/src/test/java/jp/toastkid/pair/javafx/PairTest.java)

### Pair (Eclipse Collections)
Eclipse Collections は昨年のクリスマスプレゼントです。Key と Value で別々の型を使いたい時はこちらを使います。
swap メソッドで Key と Value の入れ替えができるのが面白いです。

#### インスタンス作成
Tuples.pair(key, value)

#### キー・値の取り出し
Key は getOne() で、Value は getTwo() で可能

#### 値の変更
不可、そもそもメソッドが存在しません。間違って呼び出して Exception が発生することもありません。

なお、putというメソッドが存在します。これは Pair に値を設定するのではなく、引数で渡した Map に Pair が持つ Key と Value を入れる、というメソッドです。引数で渡した Map が unmodifiable だと Exception が発生します。

#### ほか
swap メソッドで key と value を入れ替えた Pair を取得できます。

#### テストコード
[Pair (Eclipse Collections)](https://github.com/toastkidjp/pair_verification/blob/master/src/test/java/jp/toastkid/pair/eclipse/PairTest.java)

### Twin (Eclipse Collections)
Key と Value で同じ型の場合はこちらを用います。

#### インスタンス作成
Tuples.twin(key, value)

#### キー・値の取り出し
Key は getOne() で、Value は getTwo() で可能

#### 値の変更
不可、そもそもメソッドが存在しません。間違って呼び出して Exception が発生することもありません。

なお、putというメソッドが存在するが、これは Twin に値を設定するのではなく、引数で渡した Map に Twin が持つ Key と Value を入れる、というメソッドです。引数で渡した Map が unmodifiable だと Exception が発生します。

#### ほか
swap メソッドで key と value を入れ替えた Twin を取得できます。

#### テストコード
[Twin](https://github.com/toastkidjp/pair_verification/blob/master/src/test/java/jp/toastkid/pair/eclipse/TwinTest.java)

### org.apache.commons.lang3.tuple.Pair
Apache Commons Collections に用意されています。インスタンスを作るのにファクトリメソッドを使わせたり、MutableかImmutableか選べたり、
値の取り出し方に幅を持たせてあったりと、丁寧な作りをしています。

#### インスタンス作成
1. Pair.of(key, value)
2. MutablePair.of(key, value)

#### キー・値の取り出し
Key は getKey() か getLeft() で、Value は getValue() か getRight() で可能

#### 値の変更
MutablePair は setValue() メソッドにより値だけ変更可能

Pair ないし ImmutablePair は変更不可、setValue() メソッドをコールすると UnsupportedOperationException が発生します。

#### テストコード
1. [ImmutablePair](https://github.com/toastkidjp/pair_verification/blob/master/src/test/java/jp/toastkid/pair/commons/ImmutablePairTest.java)
2. [MutablePair](https://github.com/toastkidjp/pair_verification/blob/master/src/test/java/jp/toastkid/pair/commons/MutablePairTest.java)


### 比較表
| 実装 |インスタンス作成|変更|値の取り出し|
|:--------|:----:|:----:|:----:|
| AbstractMap.SimpleEntry | new | ○ | getValue 
| AbstractMap.SimpleImmutableEntry | new | × | getValue
| javafx.util.Pair | new | × | getValue
| Eclipse Collections Pair | Tuples.pair | × | getTwo
| Eclipse Collections Twin | Tuples.twin | × | getTwo
| Apache Commons Collections MutablePair | of | ○ | getValue/getRight
| Apache Commons Collections ImmutablePair | of | × | getValue/getRight

### まとめ
OSS の利用申請が面倒等の理由がなければ、Eclipse Collections か Apache Collections を使っておけばよさそうです。

### リンク
[GitHub Repository(pair_verification)](https://github.com/toastkidjp/pair_verification)