LoginSignup
5
0

More than 5 years have passed since last update.

Javadocで稀によく見る(オプションの操作)の謎

Last updated at Posted at 2019-03-22

1.はじめに

Javadocを眺めていると目にすることのある

修飾子と型 メソッドと説明
〇〇 hoge(○○ ××)
~~~~~~(オプションの操作)

例:List(Java Platform SE8), Set(Java Platform SE8)

この意味について気にはなっていたもののググっても解説が見当たらなかった。
(もしかして常識過ぎて誰も解説してないのか。。。?)

2.規約

単刀直入に言うと以下のものが規約として存在する。

・インタフェースの実装においてオプションであるメソッドは、実装されない場合にUnsupportedOperationExceptionをスローします。どのメソッドがオプションであるかは、メソッドの説明の最後に「(オプション)」と示すことで、随時示していきます。

以上
「プログラミング言語Java 第四版」東京電機大学出版局,ケン・アーノルド ジェームズ・ゴスリン デビッド・ホームズ著,柴田芳樹訳,第四版1刷発行,502p
からの引用

3.Listインターフェースの例

ListインターフェースのJavadocには以下の10個のメソッドの説明に(オプションの操作)と書かれている。

修飾子と型 メソッドと説明
boolean add(E e)
指定された要素をこのリストの最後に追加します(オプションの操作)。
void add(int index, E element)
このリスト内の指定された位置に、指定された要素を挿入します(オプションの操作)。
boolean addAll(Collection<? extends E> c)指定されたコレクション内のすべての要素を、指定されたコレクションのイテレータによって返される順序で、このリストの最後に追加します(オプションの操作)。
boolean addAll(int index, Collection<? extends E> c)
指定されたコレクション内のすべての要素を、このリストの指定された位置に挿入します(オプションの操作)。
void clear()
すべての要素をこのリストから削除します(オプションの操作)。
E remove(int index)
このリスト内の指定された位置にある要素を削除します(オプションの操作)。
boolean remove(Object o)
指定された要素がこのリストにあれば、その最初のものをリストから削除します(オプションの操作)。
boolean removeAll(Collection<?> c)
このリストから、指定されたコレクションに含まれる要素をすべて削除します(オプションの操作)。
boolean retainAll(Collection<?> c)
このリスト内で、指定されたコレクションに含まれている要素だけを保持します(オプションの操作)。
E set(int index, E element)
このリスト内の指定された位置にある要素を、指定された要素に置き換えます(オプションの操作)。

規約によるとこれらのメソッドをListを実装したクラスのインスタンスに使った場合、「コンパイルは通るが実行時に例外が起きる」という可能性がある。

例えば、たびたび初心者が引っかかることになる
Arrays.asList(T...)や修正不可能なリストを返すCollections.unmodifiableList(list)で返されるリストがそれにあたる。

4.Arrays.asList(T...)

散々ネット上で書かれてことではあるがArrays.asList(T...)で返されるリストにはaddやremoveができない。

参考:
Java - Arrays.asList の注意点,
Arrays.asList() は単なる配列のラッパを返すだけなので、要素の追加も削除もできません

このメソッドで返されるのはListを実装した(より正確にはListを実装したAbstractListを継承した)java.util.Arrays内staticクラスのArrayListである。(java.util.ArrayListとは別物)


public static void main(String... args){
    List<String list=Arrays.asList("aaa","bbb");
    System.out.println(list.getClass());
    //->class java.util.Arrays$ArrayList
}

ソースコード
Github:jdk8/java/util/Arrays.java

読んでわかる通りadd()やremove()のメソッドがOverrideされていない。
よって親クラスのメソッドが呼ばれるが、そこにはこう書かれているので無事UnsupportOperationExceptionがスローされる。

AbstractList.java
public void add(int index, E element) {
    throw new UnsupportedOperationException();
}

ただし(オプションの操作)と記載されているメソッドのうちset()は正しく動くようにOverrideされているのでこのメソッドは例外を起こさずに使うことができる。

5.Collections.unmodifiableList(List)

これはjava.util.Collections内のstaticクラスであるUnmodifiableListかUnmodifiableRandomAccessListを返している。

Github:jdk8/java/util/Collections.java

見てわかるとおり、このクラスはオプションの操作のどのメソッドもUnsupportOperationExceptionが投げられる。

6.SubList系

subListメソッドはListインターフェースで宣言されている。よく見るやつを紹介する。

java.util.ArrayList$SubList

最もよく使われるList実装であろうArrayListのsubListメソッドを使うときに返される。オプション操作のうちすべてのメソッドを使うことができる。

java.util.ImmutableCollections$SubList

java9で追加されたList.ofで返されるListNクラス(これはImutableCollectionsクラスのstatic内部クラス)のsubListメソッドを使うと返される。全部ダメ!

7.まとめ

まあ謎の記述が理解できてよかったねって話なんですけど、、、

static内部クラスはJavadocに出ないのでオプションの操作のうちどの操作が許される操作(Arras.asListのset()など)なのかがソース見ないと分からないのは辛くないんですかね...?

5
0
0

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
5
0