Java Arrays.asList(T…)の罠




Arrays.asList(T…)は便利ですよね。
配列からリストへ変換したり、とりあえずリストのデータを作りたいときに使ったりします。

でも、Arrays.asListには罠が潜んでますw

Arrays.asList(T…)の罠のサンプル

一見すると、何の変哲もないようにも見えるコードです。

実行結果

これを実行すると、UnsupportedOperationExceptionが発生します。

UnsupportedOperationExceptionは、その名の通り、サポートされていない操作を実行したときに発生する例外です。

UnsupportedOperationExceptionの例外が発生する理由

直接の原因は、リストのaddメソッドの実行したことです。
同様に、remove,clearなどのメソッドを実行しても発生します。

非常にシンプルな原因ですが、通常のリスト操作では起こらないですよね。
ところが、Arrays.asListで作成したListオブジェクトは、このようなメソッドをサポートしていないためです。

サポートしてないってどーゆーこと?

Arrays.asListで作成されたListは、少し動作が限定されているためです。

少し古いですが、日本語のJavadocには、こうあります。

public static List asList(T… a)

指定された配列に連動する固定サイズのリストを返します。返されたリストへの変更は、そのまま配列に書き込まれます。このメソッドは、Collection.toArray()と組み合わせることで、配列ベースのAPIとコレクションベースのAPIの橋渡し役として機能します。また、返されるリストは直列化可能で、RandomAccessを実装します。

このメソッドは、次の数種類の要素を含むように初期化する固定サイズのリストを作成するための便利な方法も提供します。

List stooges = Arrays.asList(“Larry”, “Moe”, “Curly”);

Arrays(Java Platform SE 8)より

ということで、「固定サイズのリストを返します。」が問題の原因です。
サイズが変わるような操作はできない。ってことです。

逆に言うと、サイズが変わらないsetのような更新の操作はできます。

サイズを変えたいんだけど、どうすれば良いの?

方法はいろいろありますが、簡単で影響が少ない修正は、ArrayListにしてしまうことです。

この例では、ArrayListのコンストラクタを使って、ListからArrayListに変換。
その後、リストの変数にArrayListを戻しています。
つまり、1行足しただけです。

Arrays.asListは結構使うので、気を付けましょー。