【Java】コレクションフレームワーク

# コレクションとは
* **オブジェクトの集合**
* java.utulパッケージ：コレクション構造を扱うための汎用クラス/インターフェース(**コレクションフレームワーク**)を提供
* オブジェクトの集合を扱う際にまず利用したい

#Collectionインターフェース
* コレクションフレームワークの基本
* 各サブインターフェースの実装クラス
    * **List**：順序を持つ、要素は重複可能
        * ArrayList：可変長配列
        * LinkedList：リンク構造のリスト
    * **Set**：要素の重複不可
        * HashSet：任意順で格納された要素集合
        * LinkedHashSet：追加順で格納された要素集合
        * TreeSet：キーで並び替えられる要素集合
    * **Queue**：先頭/末尾要素の追加、削除。待ち行列/スタックに使う
        * ArrayDeque：両端キュー
        * LinkedList：LinkedListと同じ
    * **Map**：キー/値で管理、キーの重複不可
        * HashMap：基本Map
        * TreeMap：キーで並び替えられるMap

#コレクションのインスタンス化
* `List<String> data = new ArrayList<>();`

### **インターフェース型**
  * 変数の型(実装型)ではなくインターフェース型を用いることでクラスへの依存を最小限にできる
  * NG例：実数型をそのまま引数で渡すのは良くない<br>`ArrayList<String> data = new ArrayList<>();`<br>`public void run(ArrayList<String> data){…}`
  * →**最初からインターフェース型で`List<String>`としておけばLinkedListへの変更も容易！**
  * `List<String> data = new LinkedList<>();`
  
### **ジェネリクス構文**
  * **汎用的クラス/メソッドを特定の型に結びつける仕組み**
  * `List<String>`の場合、汎用型(List)に対してStringを割り当て、**文字列格納専用のList**になる！
  * 逆に非ジェネリクスなコレクションでは全要素をオブジェクト型(全部の型を代入できる)とみなし、明示的型キャストが必要になるし、意図しない型の値を検出できない。。<br>`Strng str = (String)data.get(0)`
  * →**型安全なジェネリクス構文を使おう！**
  * 左辺の要素型が明白な時は省略可能(**ダイアモンド演算子**)<br>`List<String> data = new ArrayList< >();`


#イディオム
## インスタンス化のタイミングでまとめてコレクション初期化

```java
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**：現在要素削除
    
```java
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`になるので注意

```java
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); //[]
  }
}
```

```java
//NG例:拡張for
    for (var s : data) {
      System.out.println(s);
      data.remove(s);
    }
```

##リストを逆順で読む
* listIteratorメソッドでListIteratorオブジェクト取得
* **previousメソッド**:前の要素に移動
* **hasPreviousメソッド**:前の要素存在確認
* listIterator引数に読み込み開始位置を指定

```java
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メソッド**で複製

```java
//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
  }
}
```

```java
//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`
    * あくまで要素をコピーしているので変換元リストへの操作は配列に影響しない

```java
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以降）

```java
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
  }
}
```

```java
//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); //[もしもしかめよ, かめさん, よ]
  }
}
```

```java
//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>();`