この記事ではJava独習の第6章(コレクションフレームワーク)についてのまとめを行います。
コンテンツは以下の通り
・コレクションフレームワークの基本
・リスト
・セット
・マップ
・スタック/キュー
6-1 コレクションフレームワークの仕組み
コレクション=オブジェクトの集合を表す仕組み
配列との違いは以下のようなものがあげられる
・既知のデータ構造やアルゴリズムを取り込むことができパフォーマンスが高い
・共通的な操作をインターフェイスとして定義しているのでデータ構造やアルゴリズムにとらわれず同じように操作可能
Collectionのサブインターインターフェイスとして以下のようなものがある
・リスト(順序を持ち重複OK)-ArrayListとLinked List
・セット(重複NG)-hashSetとLinkedHashsetとTreeSet
・マップ(キーと値の組み合わせで管理)-HahsMapとTreeMap
・スタック/キュー(戦闘と末尾の追加や削除が可能)-ArrayDequeとLinkedList
コレクションのインターフェイス化は
インターフェイス型 <要素型> = new 実装クラス型<>(引数....)
List = new ArrayList<>();
ArrayList data = new ArrayList<>();
でもいいが、実数型を引数として渡すのは望ましくない
もしLinkedList(別の実装)に変える場合全部変えなければいけないため
ジェネリクス=汎用的なクラスやメゾットを特定の型に紐づけるための仕組み
Listのように本来の汎用型のように<...>の形式で個別の型を割り当てることによってなんでもOkとするわけではなく、文字列だけになる的な
要素を順番に取り出すときはforを使用
内部的にはイテレータを利用している。イテレーターとはコレクションの要素を順番に取り出す仕組み
イテレーターのインターフェイスは以下のようなものがある
boolean has Next() 次の要素が存在するか
E next() 次の要素の取得(Eは要素の型)
void remove 現在の要素の削除
Java
import java.util.ArrayList;
public class IteratorRemove {
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);
}
}
ite.removeをコメントアウトするとこの場合バラ・ひまわり・あさがおと順番に出てきて最後に配列が表れるが、removeメゾットを使用することで配列が表れない
逆順から読み込むときはiteratorメゾットではなく、listIteratorメゾットでListIteratorメゾットを取得
Java
import java.util.ArrayList;
public class IteratorList {
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());
}
}
}
配列とコレクションの変換は以下のようにする
Java
import java.util.ArrayList;
import java.util.Arrays;
public class CollToArray {
public static void main(String[] args) {
var data = new ArrayList<String>(Arrays.asList("バラ", "ひまわり", "あさがお"));
var strs = new String[data.size()];
data.toArray(strs);
data.set(0, "チューリップ");
System.out.println(Arrays.toString(strs));
System.out.println(data);
}
}
しかし、あくまでこれは配列であるのでリストの追加や削除は配列をコピーして新規にリストを作成
Colelction.addAllメゾットを利用
Java
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
public class CollAddAll {
public static void main(String[] args) {
var data = new String[] { "バラ", "ひまわり", "あさがお"};
var list = new ArrayList<String>();
Collections.addAll(list, data);
list.set(0, "チューリップ");
list.add("さくら");
list.remove(1);
System.out.println(list);
System.out.println(Arrays.toString(data));
}
}
コレクションから配列はtoArrayメゾットつかう
Java
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
public class CollAddAll {
public static void main(String[] args) {
var data = new String[] { "バラ", "ひまわり", "あさがお"};
var list = new ArrayList<String>();
Collections.addAll(list, data);
list.set(0, "チューリップ");
list.add("さくら");
list.remove(1);
System.out.println(list);
System.out.println(Arrays.toString(data));
}
}
変更不能にするためにはunmodifiablexxxx用いる
unmodifiableListやunmodifiableMapなど
6-2 リスト
リストの実装には以下のようなものがある
ArrayList, LinkedList, Vector(なお今は使わない)
ArrayListの基本メゾット
Java
public class ListArray {
public static void main(String[] args) {
var list = new ArrayList<Integer>(Arrays.asList(10, 15, 30, 60));
var list2 = new ArrayList<Integer>(Arrays.asList(1, 5, 3, 6));
var list3 = new ArrayList<Integer>(Arrays.asList(1, 2, 3));
for (var i : list) {
System.out.println(i / 5);
}
System.out.println(list.size()); //4
System.out.println(list.get(0)); //10
System.out.println(list.contains(30)); //true
System.out.println(list.indexOf(30)); //2
System.out.println(list.lastIndexOf(30));
System.out.println(list.isEmpty());
System.out.println(list.remove(0));
System.out.println(list);
list.addAll(list2);
System.out.println(list);
list.removeAll(list3);
System.out.println(list);
list.set(0, 100);
var data = list.toArray();
System.out.println(Arrays.toString(data));
}
}
LinkedListは個別の要素のアクセスは戦闘と末尾のリンクからたどる
=インデックス値による要素の読み書きには不向きで挿入や削除は早い
Java
public class ListLinked {
public static void main(String[] args) {
var list = new LinkedList<String>(Arrays.asList("うさぎ", "たつ", "へび"));
System.out.println(list);
list.addFirst("とら");
list.addLast("うま");
System.out.println(list);
System.out.println(list.getFirst());
System.out.println(list.getLast());
System.out.println(list.removeFirst());
System.out.println(list.removeLast());
System.out.println(list);
}
}
6-3 セット
重複した要素は無視で順番を持たない集合
HashSetとLinkedHashSetとTreeSetがある
2つのセットがあるとしたら
retainAllは共通部分
removeAllは片方にあるもののみ
addAllはすべての要素
Java
public class SetBasic {
public static void main(String[] args) {
var hs = new HashSet<Integer>(Arrays.asList(1, 20, 30, 10, 30, 60, 15));
var hs2 = new HashSet<Integer>(Arrays.asList(10 ,20 ,99));
System.out.println(hs);
System.out.println(hs.size());
System.out.println(hs.isEmpty());
System.out.println(hs.contains(1));
System.out.println(hs.containsAll(hs2));
System.out.println(hs.remove(1));
System.out.println(hs);
hs.addAll(hs2);
System.out.println(hs);
hs.retainAll(hs2);
System.out.println(hs);
var hs3 = new HashSet<Integer>(Arrays.asList(1, 10 , 20));
hs.removeAll(hs3);
System.out.println(hs);
}
}
HashSetは一切並び順を管理しないが、TreeSetは並び順を管理
Java
public class SetTree {
public static void main(String[] args) {
var ts = new TreeSet<Integer>(Arrays.asList(1, 20, 30, 10, 60, 15));
System.out.println(ts);
System.out.println(ts.descendingSet());
System.out.println(ts.ceiling(15));
System.out.println(ts.lower(15));
System.out.println(ts.tailSet(15));
System.out.println(ts.headSet(30, true));
}
}
6-4 Map
一意のキーと値で管理
HashMapを最も利用するので本記事ではいったんTreeHashはおいておく
HashMapはキーの順序が保証されないので順番に意味があるものはTreemapをつかう
HashMapは内部的にハッシュ票を持っていて要素を保存するときにキーから八種値を求めてどこに保存するか決める
HashMapの基本動作
Java
public class MapHash {
public static void main(String[] args) {
var map = new HashMap<String, String>(Map.of("Rose", "バラ",
"Sunflower", "ひまわり", "Morning Glory", "あさがお"));
System.out.println(map.containsKey("Rose"));
System.out.println(map.containsValue("バラ"));
System.out.println(map.isEmpty());
for (var key : map.keySet()) {
System.out.println(key);
}
for (var value : map.values()) {
System.out.println(value);
}
map.replace("Rose", "薔薇");
map.replace("Sunflower", "ひまわり", "向日葵");
for (var entry : map.entrySet()) {
System.out.println(entry.getKey() + ":" + entry.getValue());
}
}
}
mapはコレクションのサブインターフェイスではないためfor命令に渡すことはできない
6-5 スタック
ArrayDequeは循環配列
Java
public class DequeArray {
public static void main(String[] args) {
var data = new ArrayDeque<Integer>();
data.addLast(10);
data.addLast(15);
data.addLast(30);
System.out.println(data);
System.out.println(data.removeLast());
System.out.println(data);
var data2 = new ArrayDeque<Integer>();
data2.addLast(10);
data2.addLast(15);
data2.addLast(30);
System.out.println(data2);
System.out.println(data2.removeFirst());
System.out.println(data2);
}
}