🗒️

Collectionsのメソッドを適応できるListの作り方

2022/03/31に公開約3,200字

タイトルの通り。

ざっくりとまとめると:

  • List.of()が返すリストは、immutable。Arrays.asList()が返すリストは、長さが変えられないリスト。そのため、Collectionsのメソッドでも要素の追加・削除などに関わるものは使えない
  • Collectionsのメソッドを使えるリストを作成したい場合:
     1. 新しく空のリストを作成後、add()で各要素を追加
     2. 新しく空のリストを作成後、Collections.addAll()で引数に追加したい要素を入れる

だけど、その前になぜこの記事を書こうと思ったか、きっかけとなったコードを紹介してから詳細に入る。

Listなのに、Collectionsのメソッドが使えない場合があるらしい

Listたるもの、全てCollecitonsのメソッドが使えるに違いない[1]と思って書いた以下のようなコード。残念ながらexceptionが投げられてしまう。

test.java
List<Integer> list = List.of(3, 3, 3, 4);
Collections.sort(list);     // UnsupportedOperationException

さて、この原因は、List.of()の返すリストが、immutable[2]なことによる。

https://stackoverflow.com/questions/2965747/why-do-i-get-an-unsupportedoperationexception-when-trying-to-remove-an-element-f
他にもArrays.asList()は長さの変えられないリストを返すので、このメソッドが返すリストに新たに要素を加えたり減らしたりはできない。
Integer[] array = {1,4,6,7};
List<Integer> arrayToList = Arrays.asList(array);
arrayToList.set(1, 10);
System.out.println(Arrays.toString(array));// [1,10,6,7]
System.out.println(arrayToList);           // [1,10,6,7]
arrayToList.add(20);                       // throws UnsupportedOperationException
arrayToList.remove(2);                     // throws UnsupportedOperationException

Arrays.asList(int())とArrays.asList(Integer[])の違い
でも触れたように、ここで新しくつくられたリスト型のarrayToListでの変更は、元の配列arrayにも反映される。新しいリストも、元の配列も、共にヒープ内の同じデータを参照(厳密にはpoint)してるだけなので。こういうのをan Array-backed listというらしい[3]

https://turreta.com/2016/11/20/array-backed-lists-in-java/#:~:text=In Java%2C there are these,to changing the same data

Collectionsのメソッドが使えるListを作りたい時

さて、ようやく本題ですが、Collectionsメソッドが使えるListを作りたい場合、以下の2つの方法が挙げられる。

1. ArrayList.add()

新しく空のリストを作成し、そこにadd()で要素を追加していく。for-loopで順番に要素を追加していくときなどに便利!

List<Integer> arraylist = new ArrayList<>();
arraylist.add(4);
arraylist.add(2);
System.out.println(arraylist);  // [4,2]
int i = 1;

while(arraylist.size() < 10){
    arraylist.add(++i);
}
System.out.println(arraylist);

2. Collections.addAll()

新しい空のリストを作成するのは、上記の方法と共通だが、その後に格納する要素をワンラインで格納できるのが、このメソッド。

public static <T> boolean addAll(Collection<? super T> c, T.. a)

このメソッドは、c.addAll(Arrays.asList(elements))を行っている。ほかの方法で要素追加もできるが、大抵の場合はこのメソッドの方が早い(と、以下の公式ドキュメントがおっしゃっている)。

https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/Collections.html#addAll(java.util.Collection,T...)

List<String> browserlist = new ArrayList<>();
Collections.addAll(browserlist, "Google", "Mozila FireFox", "Yahoo");
browserlist.add("Opera");
System.out.println(browserlist);
    // [Google, Mozila FireFox, Yahoo, Opera]

test.java書き直し

test.java
List<Integer> list = new ArrayList<>();
Collections.addAll(list, 1,4,2,3,2,5);
Collections.sort(list);                // [5, 4, 3, 2, 2, 1]
脚注
  1. だってListCollectionsのインターフェースだから!Collections in Java: Hierarchy of Collection Framework ↩︎

  2. 不可変とでも言うのかな。String型もimmutableで値が変えられない。軽く調べても、浸透している共通語はなさそうだったので、便宜上英語のままにします。 ↩︎

  3. a backed listということも('Chapter 5: Core Java APIs' from "OCP Oracle Certified Professional Java SE 11 Programmer I Study Guide: Exam 1Z0-815")。そして例によって、また対応する日本語分カラナイヨ。このあたりの用語がまとまった記事も、そのうち作りたい。 ↩︎

Discussion

ログインするとコメントできます