コレクションとは
- オブジェクトの集合
- java.utulパッケージ:コレクション構造を扱うための汎用クラス/インターフェース(コレクションフレームワーク)を提供
- オブジェクトの集合を扱う際にまず利用したい
Collectionインターフェース
- コレクションフレームワークの基本
- 各サブインターフェースの実装クラス
-
List:順序を持つ、要素は重複可能
- ArrayList:可変長配列
- LinkedList:リンク構造のリスト
-
Set:要素の重複不可
- HashSet:任意順で格納された要素集合
- LinkedHashSet:追加順で格納された要素集合
- TreeSet:キーで並び替えられる要素集合
-
Queue:先頭/末尾要素の追加、削除。待ち行列/スタックに使う
- ArrayDeque:両端キュー
- LinkedList:LinkedListと同じ
-
Map:キー/値で管理、キーの重複不可
- HashMap:基本Map
- TreeMap:キーで並び替えられるMap
-
List:順序を持つ、要素は重複可能
コレクションのインスタンス化
List<String> data = new ArrayList<>();
インターフェース型
- 変数の型(実装型)ではなくインターフェース型を用いることでクラスへの依存を最小限にできる
- NG例:実数型をそのまま引数で渡すのは良くない
ArrayList<String> data = new ArrayList<>();
public void run(ArrayList<String> data){…}
- →最初からインターフェース型で
List<String>
としておけばLinkedListへの変更も容易! List<String> data = new LinkedList<>();
ジェネリクス構文
- 汎用的クラス/メソッドを特定の型に結びつける仕組み
-
List<String>
の場合、汎用型(List)に対してStringを割り当て、文字列格納専用のListになる! - 逆に非ジェネリクスなコレクションでは全要素をオブジェクト型(全部の型を代入できる)とみなし、明示的型キャストが必要になるし、意図しない型の値を検出できない。。
Strng str = (String)data.get(0)
- →型安全なジェネリクス構文を使おう!
- 左辺の要素型が明白な時は省略可能(ダイアモンド演算子)
List<String> data = new ArrayList< >();
イディオム
インスタンス化のタイミングでまとめてコレクション初期化
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
//匿名クラス
var data = new ArrayList<String>() {
//初期化ブロック
{
add("neko");
add("inu");
add("tori");
}
};
System.out.println(data);//[neko, inu, tori]
}
}
拡張forでコレクション配下を順に処理
* 内部では**Iterator**を使用したwhile命令のシンタックスシュガー(簡単化した構文)
* Iteratorインターフェースのメソッド
* **hasNext**:次の要素存在確認
* **next**:次の要素に移動&取得
* **remove**:現在要素削除
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
var data = new ArrayList<String>() {
{
add("neko");
add("inu");
add("kuma");
}
};
//コレクション配下を順に処理
for (var s : data) {
System.out.println(s); //neko inu kuma
}
// イテレーターを使った場合
// var itr = data.iterator();
// while (itr.hasNext()) {
// System.out.println(itr.next());
// }
}
}
ループで要素削除
- 拡張forでは
ConcurrentModificationException
になるので注意
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
var data = new ArrayList<String>() {
{
add("neko");
add("inu");
add("niwatori");
}
};
var ite = data.iterator();
while (ite.hasNext()) {
System.out.println(ite.next()); //neko inu niwatori
ite.remove();
}
System.out.println(data); //[]
}
}
//NG例:拡張for
for (var s : data) {
System.out.println(s);
data.remove(s);
}
リストを逆順で読む
- listIteratorメソッドでListIteratorオブジェクト取得
- previousメソッド:前の要素に移動
- hasPreviousメソッド:前の要素存在確認
- listIterator引数に読み込み開始位置を指定
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
var data = new ArrayList<String>() {
{
add("neko");
add("inu");
add("shimaenaga");
}
};
//末尾を開始位置に設定
var ite = data.listIterator(data.size());
while (ite.hasPrevious()) {
System.out.println(ite.previous()); //shimaenaga inu neko
}
}
}
配列とコレクションの変換
- 基本はオブジェクトの集合は配列よりコレクション(オブジェクト指向構文との親和性)
配列からリストへ
-
asListメソッド
- 変換したリストはあくまでもリストの皮を被った配列!
- リストの変更は元の配列に影響、リストへの追加、削除はできない
- →Collections.addAllメソッドで複製
//NG例:既存文字列をリストに変換、変換後のリストに値を追加削除
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
var data = new String[] { "cat", "dog", "bird"};
var list = Arrays.asList(data);
list.set(0, "neko");
System.out.println(list); //[neko, dog, bird]
System.out.println(Arrays.toString(data)); //[neko, dog, bird]
//list.add("inu"); //UnsupportedOperationException
//list.remove(0); //UnsupportedOperationException
}
}
//OK例:既存文字列をリストに変換、変換後のリストに値を追加削除
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
public class Main {
public static void main(String[] args) {
var data = new String[] { "cat", "dog", "bird" };
var list = new ArrayList<String>();
Collections.addAll(list, data);
list.set(0, "neko");
list.add("inu");
System.out.println(list); //[neko, dog, bird, inu]
list.remove(1);
System.out.println(list); //[neko, bird, inu]
System.out.println(Arrays.toString(data)); //[cat, dog, bird]
}
}
コレクションから配列へ
-
toArrayメソッド
- 引数の配列に全要素が収まるならその要素を設定
- 収まらないなら引数と同じ方の配列を生成してから全要素設定
- コレクション要素を配列要素型に変換できない場合
ArrayStoreException
- あくまで要素をコピーしているので変換元リストへの操作は配列に影響しない
import java.util.ArrayList;
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
var data = new ArrayList<String>(Arrays.asList("cat", "dog", "bird"));
//リストと同じサイズの配列strsに中身コピー
var strs = new String[data.size()];
data.toArray(strs);
//変換元リストのみデータ追加
data.set(0, "neko");
System.out.println(Arrays.toString(strs)); //[cat, dog, bird]
//変換元リストのみ変わってる
System.out.println(data); //[neko, dog, bird]
}
}
変更不可コレクションへの変換
-
unmodifiableメソッド
- 変更しようとすると
UnsupportedOperationException
- 要素が参照型の場合、内容変更を制限できないことも(StringBuilderなど)
- ofメソッドでも変更不能コレクション直接生成できる(Java9以降)
- 変更しようとすると
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
public class Main {
public static void main(String[] args) {
var data = new ArrayList<String>(Arrays.asList("cat", "dog", "bird"));
//変更不能なlistを生成
var udata = Collections.unmodifiableList(data);
udata.set(0, "neko"); //UnsupportedOperationException
udata.add("inu"); //UnsupportedOperationException
}
}
//StringBuilderではコレクション要素内容変更可能
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
public class Main {
public static void main(String[] args) {
var data = new ArrayList<StringBuilder>(Arrays.asList(
new StringBuilder("もしもし"),
new StringBuilder("かめさん"),
new StringBuilder("よ")));
var udata = Collections.unmodifiableList(data);
udata.get(0).append("かめよ");
System.out.println(udata); //[もしもしかめよ, かめさん, よ]
}
}
//ofメソッドで変更不能コレクション直接生成
import java.util.List;
public class Main {
public static void main(String[] args) {
var data = List.of("cat", "dog", "bird");
System.out.println(data);
data.set(0, "neko"); //UnsupportedOperationException
}
}
空コレクション生成
- 戻り値がコレクションのメソッドでは、戻り値が空の場合nullではなくからコレクションを返す
- emptyList / emptySet / emptyMapメソッド
return Collections.emptyList();
同期化コレクション生成
-
同期化コレクション:マルチスレッド対応(=排他処理)するためのメソッド
- synchronizedCollection / synchronizedList / synchronizedSet / synchronizedMapメソッド
- マルチスレッド環境で安全に利用できる (=スレッドセーフ)
var data = Collections.synchronizedList(new ArrayList<String>());
- より性能のいい並列コレクション生成
- CopyOnWriteArrayList / CopyOnWriteArraySet / ConcurrentHashMap
var map = new ConcurrentHashMap<String,String>();