コレクションとは?
モノ(オブジェクト)の集合を表す仕組みです。
javaでは、数多くのコレクションの構造、操作の手段(=アルゴリズム)を、標準ライブラリ(java.utilパッケージ)として提供されているそうです。
java.utilパッケージは、コレクションを扱うための汎用的なクラス/インターフェイスの集合です。これを総称して、コレクションフレームワークと呼ぶそうです。
よく聞くインターフェイスとは何か?
「インターフェース」は、コンピューター業界やIT業界でよく使われる言葉です。英語の「Interface」が語源となっています。
英単語の「Interface」の直訳は「境界面」「接点」であり、ビジネス用語の「インターフェース」はここから「異なる2つのものを仲介する」という意味で使われます。
コンピューター関連の用語として、「異なる2つの機器を仲介する」という意味のIT用語として使用されるケースが多いので、コンピューター業界やIT業界で働いている人にとっては、なじみのあるビジネス用語かもしれませんね。
コレクションの基本構文
コレクションは、一般的に以下の構文でインスタンス化します。
インターフェイス型<要素型> = new 実装クラス型<>(引数, ...)
たとえばArrayListクラスをインスタンス化するには、以下のように表します。
List<String> data = new ArrayList<>();
ジェネリクス構文
ジェネリクス(Generics)とは、一言で言うと、汎用的なクラス/メソッドを特定の型にひもづけるための仕組みです。Listのように、本来の汎用型(ここではList)に対して、<...>の形式で個別の型(ここではString)を割り当てることで、(なんでも格納できるリストではなく)文字列を格納するための専用リストになります。
コードを実際に書いてみる
コレクション配下の要素を順番に処理するには、拡張for命令を利用します
Main.java
package com.company;
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
var data = new ArrayList<String>() { // ここは匿名クラスというらしい?
{ // ここは初期化ブロックというらしい?
add("バラ");
add("ひまわり");
add("あさがお");
}
};
for (var s : data) {
System.out.println(s);
}
}
}
実行結果
バラ
ひまわり
あさがお
この拡張for命令、内部的にはイテレーターを利用したwhile命令のシンタックスシュガー(より簡単化された構文)です。イテレーターとは、コレクションの要素を順番に取り出すための仕組みです。
拡張forの方がコードをシンプルに表現できることから、一般的にはいてレーターを直接利用する機会はほとんどないそうです。
イテレーターで拡張forを書き換えるとこのように書く
var ite = data.iterator();
while (ite.hasNext()) {
System.out.println(ite.next());
}
コレクションからはiteratorメソッドを利用することで、それぞれの実装に応じたIteratorオブジェクト(イテレーター)を取得できます。Iteratorで利用できるメソッドは以下の通りです。
メソッド | 概要 |
---|---|
boolean hasNext() | 次の要素が存在するか |
E next() | 次の要素を取得(Eは要素の型) |
void remove() | 現在の(nextメソッドで取得した最後の要素)を削除 |
ループの中で要素を削除したい
たとえばループしながら、要素を削除するには、イテレーターを利用します
Main.java
package com.company;
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
var data = new ArrayList<String>() { // ここは匿名クラスというらしい?
{ // ここは初期化ブロックというらしい?
add("バラ");
add("ひまわり");
add("あさがお");
}
};
var ite = data.iterator();
while (ite.hasNext()) {
System.out.println(ite.next());
ite.remove();
}
System.out.println(data);
}
}
実行結果
バラ
ひまわり
あさがお
[]
拡張forで書いてもよさそうですが、こちらでは例外が発生する。
Main.java
package com.company;
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
var data = new ArrayList<String>() { // ここは匿名クラスというらしい?
{ // ここは初期化ブロックというらしい?
add("バラ");
add("ひまわり");
add("あさがお");
}
};
for (var s : data) {
System.out.println(s);
data.remove(s);
}
}
}
実行結果
バラ
Exception in thread "main" java.util.ConcurrentModificationException
at java.base/java.util.ArrayList$Itr.checkForComodification(ArrayList.java:1043)
at java.base/java.util.ArrayList$Itr.next(ArrayList.java:997)
at com.company.Main.main(Main.java:15)
プロセスは終了コード 1 で終了しました
リストを逆順に読み込む
リストを逆順に読み出す際にも、いてレーターを利用します。この場合はlistIteratorメソッドでListIteratorオブジェクトを取得します。
ListIteratorを利用して、リストを逆順に出力する例
Main.java
package com.company;
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
var data = new ArrayList<String>() { // ここは匿名クラスというらしい?
{ // ここは初期化ブロックというらしい?
add("バラ");
add("ひまわり");
add("あさがお");
}
};
var ite = data.listIterator(data.size());
while (ite.hasPrevious()) {
System.out.println(ite.previous());
}
}
}
実行結果
あさがお
ひまわり
バラ
listIteratorメソッドの引数には、イテレーターで読み込むべき開始位置を指定します。この例ではリストサイズ(=末尾)を指定しています。