[Java] コレクションの操作(ジェネリクス構文)

オブジェクトの集合を扱う。

以下の理由からアプリ内で集合を扱う場合には、配列ではなくまずコレクションを利用すべきとのこと。

  • 既知のデータ構造/アルゴリズムをそのまま取り込めるため、開発生産性に優れる。
  • 同様の理由からパフォーマンスにも優れる。
  • 共通的な操作をインターフェースとして定義しているので、データ構造/アルゴリズムによらず、同じように操作できる。

Contents

基本構文

通常は簡潔に書ける var 型推論を利用する。

var data = new ArrayList();

変数型を強く意識する場合は、インターフェース型を利用する。

List<String> data = new ArrayList<>();

見慣れない List<> は Generics 構文で、汎用的なクラス・メソッドを特定の型に結びつけるための仕組み。
格納する値の型が正しいことをコンパイル時にチェックでき、値を取り出す場合のキャストも不要になる。 => (型安全)

リスト

一般的には、以下で使い分ける。

  • LinkedList … 連続して要素の挿入/削除が発生する、あるいはリストに順にアクセスする用途。
  • ArrayList … それ以外の既存要素の取得や書き換えが主となる用途。
package com.example.arrayloop;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;

public class ArrayLoop {
    private static String msg;

    public static void main(String[] args) throws Exception {
        StringBuilder msg = new StringBuilder();
        // int[] array = {50, 60, 70, 80};
        // var array = new ArrayList<Integer>(Arrays.asList(50, 60, 70, 80));
        var array = new LinkedList<Integer>(Arrays.asList(50, 60, 70, 80));
        for (int mps : array) {
            var kmh = mps * 3600 / 1000;
            msg.append("最大瞬間風速").append(mps).append("m = 時速").append(kmh).append("km").append("\n");
            setMsg(msg.toString());
        }

        System.out.println(msg);
    }

    private static void setMsg(String msgString) {
        msg = msgString;
    }
}

セット

HashSet 数学における集合の概念に似ている。重複を許さない。
並び順は管理しない。

import java.util.HashSet;
    :
var set = new HashSet<Integer>(Arrays.asList(1, 20, 30, 1, 60, 20));
System.out.println(set); // [1, 20, 60, 30]

TreeSet は、順番も持っている。

import java.util.TreeSet;
    :
var set = new TreeSet<Integer>(Arrays.asList(1, 20, 30, 1, 60, 20));
System.out.println(set); // [1, 20, 30, 60]

マップ

一意のキーと値のペアで管理されるデータ構造。
ディクショナリ、ハッシュ、連想配列に該当する。

唯一、Collection インターフェースを継承していないデータ構造。
そのまま拡張 for に渡すことが出来ない。

HashMap 最も基本的な実装。
キーの順序は保証されない。

import java.util.HashMap;
import java.util.Map;
    :
var map = new HashMap<String, String>(Map.of("Rose", "バラ", "Sunflower", "ひまわり", "Morning Glory", "あさがお"));
for (var entry : map.entrySet()) {
    System.out.println(entry.getKey() + ":" + entry.getValue());
}
// Rose:バラ
// Sunflower:ひまわり
// Morning Glory:あさがお

TreeMap は順番に意味のある操作に利用する。

import java.util.TreeMap;
    :
var map = new TreeMap<String, String>(Map.of("Rose", "バラ", "Sunflower", "ひまわり", "Morning Glory", "あさがお"));
for (var entry : map.entrySet()) {
    System.out.println(entry.getKey() + ":" + entry.getValue());
}
// Morning Glory:あさがお
// Rose:バラ
// Sunflower:ひまわり

key, value ペアが分かりづらい。

スタック/キュー

ArrayDeque を利用する。

Stack (Last In First Out)

import java.util.ArrayDeque;
    :
var data = new ArrayDeque<Integer>();
data.addLast(10);
data.addLast(15);
data.addLast(30);

System.out.println(data); // [10, 15, 30]
System.out.println(data.removeLast()); // 30
System.out.println(data); // [10, 15]

Queue (First In First Out)

import java.util.ArrayDeque;
    :
var data = new ArrayDeque<Integer>();
data.addLast(10);
data.addLast(15);
data.addLast(30);

System.out.println(data); // [10, 15, 30]
System.out.println(data.removeFirst()); // 10
System.out.println(data); // [15, 30]