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がスローされる。
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()など)なのかがソース見ないと分からないのは辛くないんですかね...?