Item 31: Use bounded wildcards to increase API flexibility

# 31.APIの柔軟性のために境界ワイルドカードを使用すべし

Item28でもあったように、型パラメータはinvariantである。よって、例えば、```List<String>```は```List<Object>```のサブタイプではない。```List<Object>```のできることすべてが、```List<String>```にできるわけではないので、リスコフの置換原則にも符合する。（Item10）
時には、もっと柔軟性が必要となることがある。Item29で使用したStackクラスを例に考えてみる。StackクラスのAPIは以下のよう。

```java
public class Stack<E> {
    public Stack();
    public void push(E e);
    public E pop();
    public boolean isEmpty();
}
```
ここに要素のシーケンスを引数にとり、それらをすべてStackにのせるメソッドを追加することを考える。最初に考えるのは以下のようなものだろう。

```java
// pushAll method without wildcard type - deficient!
public void pushAll(Iterable<E> src) {
    for (E e : src)
        push(e);
}
```

このメソッドはコンパイルできるが、満足いくものではない。```Iterable<E> src```の要素がStackの要素と一致すればうまく動くが、例えば、以下のようなコードはエラーとなる。エラーの理由は、型パラメータはinvariantだからである。

```java
Stack<Number> numberStack = new Stack<>();
Iterable<Integer> integers = ... ;
numberStack.pushAll(integers);
```

ここで出てくるエラーに対処するためには、型引数にワイルドカードを用いる。

```java
// Wildcard type for a parameter that serves as an E producer
public void pushAll(Iterable<? extends E> src) {
    for (E e : src)
        push(e);
}
```
この対応によって、コンパイルできるようになり、タイプセーフにもなる。

次に、collectionを引数にとり、Stackにたまっている要素をすべてそれに移す、```popAll```メソッドを考えてみる。素案は以下のよう。

```java
// popAll method without wildcard type - deficient!
public void popAll(Collection<E> dst) {
    while (!isEmpty())
        dst.add(pop());
}
```
これは要素EがStackのそれと完全に一致した場合にはうまく動くが、そうでない場合は動かない。つまり、以下のコードはコンパイルエラーとなる。

```java
Stack<Number> numberStack = new Stack<Number>();
Collection<Object> objects = ... ;
numberStack.popAll(objects);
```
対処するためには、以下のようにここでも型引数にワイルドカードを用いる。

```java
// Wildcard type for parameter that serves as an E consumer
public void popAll(Collection<? super E> dst) {
    while (!isEmpty())
        dst.add(pop());
}
```

ここでの教訓は明確で、**インプットされる引数が、producerまたは、consumerのどちらかの役割を果たすときワイルドカードを使う**、ということである。
インプットされる引数がproducer、consumerのどちらの役割も果たす場合には、ワイルドカードを使う必要はない。
使いどころは以下のように記憶する。

```
PECS stands for producer-extends, consumer-super.
```
これはつまり、型変数Tがproducerである場合には、```<? extends T>```を用い、consumerである場合には```<? super T>```を用いるということを表している。上のStackの例もそのようになっている。

このPECSの具体例を本章の例に適用していく。
Item28の以下のコンストラクタについて考える。

```java
public Chooser(Collection<T> choices)
```
この引数はproducerの役割を果たすので、PECSに従い、以下のようになる。

```java
// Wildcard type for parameter that serves as an T producer
public Chooser(Collection<? extends T> choices)
```

次に、Item30の以下のunionメソッドについて考える。

```java
public static <E> Set<E> union(Set<E> s1, Set<E> s2)
```
引数はどちらもproducerの役割を担うため、以下のようになる。

```java
public static <E> Set<E> union(Set<? extends E> s1,
                               Set<? extends E> s2)
```
ここでの注意点は、**戻り値の型には境界ワイルドカードを使ってはならない**ということだ。
そのような対応は、ユーザにとって柔軟性が増すというより、クライアントのコードの中でワイルドカードを使うことを強いることになる。
**クラスの使用に当たって、ユーザが境界ワイルドカードのことを考えないといけないのは、そのAPIに問題があると考えられる。**

Java8より前だと以下のように型を明示してやらねばならない。

```java
// Explicit type parameter - required prior to Java 8
Set<Number> numbers = Union.<Number>union(integers, doubles);
```

次に、Item30のmaxメソッドについて考える。

```java
public static <T extends Comparable<T>> T max(List<T> list)
```
これをPECSに当てはめると、以下のようになる。

```java
public static <T extends Comparable<? super T>> T max(
        List<? extends T> list)
```
ここでは2回PECSを当てはめている。
**Comparableは常にconsumerなので、```Comparable<T>```より```Comparable<? super T>```を選択するべき**。
**Comparatorも同様なので、```Comparator<T>```より```Comparator<? super T>```を選択するべき**。

そのほかに、ワイルドカード関連で議論すべきは、型パラメータを使うべきか、ワイルドカードを使うべきかの問題がある。
例えば、listのスワップを行うメソッドは、型パラメータを使用した場合と、ワイルドカードを使用した場合の2通りが考えられる。

```java
// Two possible declarations for the swap method
public static <E> void swap(List<E> list, int i, int j);
public static void swap(List<?> list, int i, int j);
```
どちらが好まれるかというと、2つ目のワイルドカードを使用したメソッドの方がシンプルであるので好まれる。
一般に**型変数がメソッド内の一か所にしか現れない場合には、ワイルドカードに置き換えるべきである。**
2つ目のメソッドは以下のように、それだけを書くとコンパイルエラーとなる。

```java
public static void swap(List<?> list, int i, int j) {
    list.set(i, list.set(j, list.get(i)));
}
```

```
型 List<capture#2-of ?> のメソッド set(int, capture#2-of ?) は引数 (int, capture#3-of ?) に適用できません
```
これを解消するためには、ワイルドカードを型にはめるヘルパークラスを作成する。

```java
package tryAny.effectiveJava;

import java.util.List;

public class GenericesTest9 {
    public static void swap(List<?> list, int i, int j) {
        swapHelper(list, i, j);
    }

    // Private helper method for wildcard capture
    private static <E> void swapHelper(List<E> list, int i, int j) {
        list.set(i, list.set(j, list.get(i)));
    }

}
```
こうすることによって、実装が多少複雑になるが、ユーザにはシンプルなswapメソッドを見せることができる。