Collections.addAllとArrays.asList
ジェネリックメソッドで可変長引数を使うと警告が出るでSetにデータを詰めるのに Collections.addAll を使ったんだけど、この手のもので、変数宣言と同時に使われる記法としては Arrays.asList を使うアイデアがある。private static final Set<String> fruits = new HashSet<>(Arrays.asList("1", "2", "3"));
Collections.addAllとArrays.asListのインターフェースは以下のようになっている。
public static <T> boolean addAll(Collection<? super T> c, T... elements)
https://docs.oracle.com/javase/jp/8/docs/api/java/util/Collections.html#addAll-java.util.Collection-T...-
public static <T> List<T> asList(T... a)
https://docs.oracle.com/javase/jp/8/docs/api/java/util/Arrays.html#asList-T...-
Arrays.asListはListに特化しているというのはあるにせよ、どちらも、型変数の可変長引数を受け取って、Collectionに可変長引数の値を詰め込んでいる。
ここで違うのはCollections.addAllの格納先の型パラメータは<? super T>となっていて、Arrays.asListは<T>となっているところ。
どちらも T... a の格納先なので、<? super T>でいいような気がするけど、なんでArrays.asListは<T>になってるんだろうか?
メソッドを使う側は?
Guidelines for Wildcard UseThese guidelines do not apply to a method's return type. Using a wildcard as a return type should be avoided because it forces programmers using the code to deal with wildcards.
とあるように、戻り値の型にワイルドカードを使ってしまうと、このメソッドを呼ぶ側にもワイルドカードの使用を強いることになってしまう。
private static final Set<? super String> fruits = readOnlySet("apple", "banana", "orange"); private static <T> Set<? super String> readOnlySet(T ... a) { Set<? super String> set = new HashSet<>(a.length); Collections.addAll(set, a); return Collections.unmodifiableSet(set); }
今回の場合は不変のリストだからまだいいけど、リストを別の変数に代入するとこれはちょっとまずいことになる。
Guidelines for Wildcard Use では <? extends ...> の例が載っているので、 <? super ...> で試してみよう。
Set<String> sstring = new HashSet<>(); Set<? super String> sobject = new HashSet<>(); sobject = sstring; sobject.add("foo"); sobject.add(new Object()); // コンパイルエラー!
この場合、sobjectにStringのスーパークラス型の変数をaddしようとした時点でコンパイルエラーになってしまう。
というわけで、ジェネリックメソッドの戻り値にワイルドカードは使わない方がいいみたい。
0 件のコメント:
コメントを投稿