5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Arraysクラスの asList の罠

Posted at

はじめに

最近、Arraysをよく使うことがあり、そのせいでハマったことがあるので
メモということで記します。

配列を作るには

Javaで配列を使用する場合、以下2つの方法がある。
new を使用して生成する場合と、ArraysクラスのasListを使って生成する方法。

  • new ArrayList<T>()

    // 配列を生成
    List<String> hoge = new AraryList<String>();
    
    // 要素を追加
    hoge.add("test1");
    hoge.add("test2");
    
  • Arrays.<T>asList()

    // 配列を生成
    List<String> hoge = Arrays.<String>asList("test1", "test2");
    

どちらも「test1」「test2」を持った文字列配列を作ることができます。

配列操作してみる

配列を作成したので、追加/編集/削除 を行ってみる。
テストコードはこんな感じ

sample.java:Arraysを使ったケース
@Test
public void test_sample() {

    List<String> test = Arrays.<String>asList("aaa", "bbb");

    // 1.要素を追加
    test.add("ccc");

    // 2.要素を削除
    test.remove(1);

    // 3.要素を編集
    test.set(1, "ddd");

    // 4.要素を全クリア
    test.clear();
}

これを実行してみると、3のケース以外では
java.lang.UnsupportedOperationException が発生してしまいます。

では、new を使ったケースではどうか。

sample2.java:newを使ったケース
@Test
public void test_sample2() {

    List<String> test = new ArrayList<>();
    test.add("aaa");
    test.add("bbb");

    // 1.要素を追加
    test.add("ccc");

    // 2.要素を削除
    test.remove(1);

    // 3.要素を編集
    test.set(1, "ddd");

    // 4.要素を全クリア
    test.clear();
}

こちらの場合、実行してもエラーが発生せず、以下のような結果となります。

1のケース後の配列の中身:aaa, bbb, ccc
2のケース後の配列の中身:aaa, ccc
3のケース後の配列の中身:aaa, ddd
4のケース後の配列の中身:空っぽ

なぜか?

どちらも同じ配列操作をしているだけなのに、なぜ違いが出るのか。
new を使うと動的に配列を生成しますが、ArraysクラスのasListの場合

固定サイズのリスト を返すからです。

JavaのAPI仕様書にも記載されていました。
クラスArrays より抜粋

修飾子と型 メソッドの説明
static <T> List<T> asList(T... a)
指定された配列に連動する
固定サイズのリストを返します

固定サイズのリストとは?

newを使った場合は指定要素のオブジェクトを
生成します。そのため実体が存在します

しかし、Arrays.asListの場合、指定した
要素の内容を保持したリストのように
見せかけているだけなので、固定サイズ(固定数)
のリストとなり、追加/削除といったリストの
数に関する操作を行うと、前述したようにUnsupportedOperationExceptionのエラーが発生してしまいます。

まとめ

Arrays.asListで生成したリストは要素数の操作を
行うことはできないので、動的なリストを使った
処理には向きません(普通使わないと思いますが)

しかし、決まった要素数(変わり得ない)でリスト型で扱いたいときには、newで生成したオブジェクトにaddして行うよりも不用意なメモリを確保しないので個人的にはいいと思ってます。

※newで配列数を指定しないとデフォルトでは
10個分のメモリを確保してしまうので
StringやIntegerのようなものであれば
微々たるものかもですが、自前の大きなクラスの
場合だとチリも積もれば……ですので

5
1
2

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
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?