目的
- Javaのコレクションフレームワークの1つである List について、整理してみます。
- 各クラスやメソッドの詳細な説明はしません。
主要なクラス
- java.util.ArrayList
-
- 配列型のリスト
- ランダムアクセスが速い
- 先頭や途中の要素の追加・削除には配列のコピーが必要なため遅い
- java.util.LinkedList
-
- 線形リスト型のリスト
- ランダムアクセスは遅い
- 先頭や途中での要素の追加・削除は高速に動作する
- java.util.Vector
-
- 古いコレクションフレームワーク
- 基本的にメソッドごとに同期される
- 基本使わないこと
便利なメソッド
基本はユーティリティクラスの java.util.Collections
クラスにまとまっています。
また java.util.List
(あるいはその親の java.util.Collection
)にも便利なメソッドがあります。
配列との相互変換
java.util.Arrays#asList()
java.util.Collection#toArray()
詳細は 配列のメモ を参照。
EnumerationからListへの変換
java.util.Collections#list()
一度、全部読み込んでリストに詰め替えてしまいます。
Properties properties = System.getProperties();
Enumeration<?> keyNames = properties.propertyNames();
List<?> list = Collections.list(keyNames);
for (Object prop : list) {
System.out.println(prop);
}
Streamとの相互変換
java.util.Collection#stream()
-
java.util.stream.Stream#collect()
とjava.util.stream.Collectors#toList()
の組み合わせ
List<String> list = Arrays.asList("Alfa", "Bravo", "Charlie");
List<String> result = list.stream()
.filter((s) -> s.contains("o"))
.collect(Collectors.toList());
System.out.println(result); // -> "[Bravo]"
JDK16 からは Strem#toList()
が追加されました。これにより少しだけ短く書くことができるようになりました。
ただし Strem#toList()
はイミュータブル(変更不可)なリストを返すことが javadoc に明記されているためご注意ください。
List<String> list = Arrays.asList("Alfa", "Bravo", "Charlie");
List<String> result = list.stream()
.filter((s) -> s.contains("o"))
.toList(); // <- 短く!
System.out.println(result); // -> "[Bravo]"
(ちなみに Collectors#toList()
に関しては、実装上はミュータブル(変更可能)なリストを返しているようですが、javadoc には「返されるListの型、可変性、直列化可能性、またはスレッド安全性は一切保証されません。」と記載があり、ミュータブルであることは保証されていませんでした。余談ですが Collectors#toUnmodifiableList()
というイミュータブルなリストを返すことを保証するメソッドもあります)
空のリスト
java.util.Collections#emptyList()
空のリストが必要な場合には、無駄に new ArrayList()
でインスタンスを生成しないで、イミュータブルなオブジェクトを使いまわすほうが良いかと。
変更不可なので注意。
java.util.List#of()
Java 9 からは、変更不可の空リストを List#of()
でも書けるようになりました。
こっちのほうが短いですね。
要素が1つだけの変更不可リスト
java.util.Collections#singletonList()
変更不可なので注意。
java.util.List#of(E)
Java 9 からは、1要素の変更不可リストを簡単に作れるようになりました。
こっちのほうが短いですね。
変更不可リスト化
java.util.Collections#unmodifiableList()
リストを定数的に使いたいときによくお世話になりました。
java.util.List#of(E...)
ただし、Java 9 からは、変更不可リストを直接作れるようになりました。
こっちのほうが短くてわかりやすいですね。
同期リスト化
java.util.Collections#synchronizedList()
動的型保証
java.util.Collections#checkedList()
その他
-
java.util.Collections#addAll()
- まとめて追加 -
java.util.Collections#copy()
- コピー -
java.util.Collections#fill()
- 値の設定(リストのサイズは変わらない) -
java.util.Collections#shuffle()
- シャッフル - いろいろ
subList()
メソッド
リストの部分リストのインスタンスを返す subList()
ですが、リストの要素は基になったリストと共有されています。
つまり部分リストを変更すれば本体のリストも変更されますし、逆に本体のリストを変更すれば部分リストも変更されます。
List<String> list = new ArrayList<>();
Collections.addAll(list, "Alfa", "Bravo", "Charlie", "Delta", "Echo", "Foxtrot");
List<String> subList = list.subList(1, 3);
System.out.println(subList); // -> "[Bravo, Charlie]"
subList.set(0, "x");
System.out.println(subList); // -> "[x, Charlie]"
System.out.println(list); // -> "[Alfa, x, Charlie, Delta, Echo, Foxtrot]"
これを利用して、リストの部分削除や置換なども可能です。
List<String> list = new ArrayList<>();
Collections.addAll(list, "Alfa", "Bravo", "Charlie", "Delta", "Echo", "Foxtrot");
list.subList(1, 3).clear();
System.out.println(list); // -> "[Alfa, Delta, Echo, Foxtrot]"
必要なのは部分リストだけの場合には、本体のリストをいつまでも保持しているのは無駄なので、改めて部分リストを作り直したほうが良い場合もあります。
public List<String> getXxxList() {
// 巨大なリストを取得してしまった
List<String> hugeList = getHugeList();
// 必要なのは一部だけ
List<String> subList = new ArrayList<>(hugeList.subList(1, 3));
return subList;
}
java.util.RandomAccess
インタフェース
自分で List クラスを作った場合、ランダムアクセス可能なつくりであれば RandomAccess
インタフェースを実装した方が良いと思います。
不変リストの初期化
定数的な使い方をしたいために、不変リストを生成するこは比較的多くあると思います。
そんなときに毎回 Collections#unmodifiableList()
と Arrays#asList()
を組み合わせて使っていると、書くのが面倒なので、以下のようなメソッドを作ることがありました。
@SafeVarargs
public static <E> List<E> toConstList(E... data) {
int length = (data == null) ? 0 : data.length;
switch (length) {
case 0:
return Collections.emptyList();
case 1:
return Collections.singletonList(data[0]);
default:
return Collections.unmodifiableList(Arrays.asList(data));
}
}
たいていの場合、最後の default
の部分だけでいいんですけどね。
Java 9 では、前述のように変更不可リストをいきなり生成できるようになりました。
便利ですね。
private static final List<String> NAMES = List.of("Foo", "Bar", "Baz");