ヘッダー画像

Javaのコレクション「Set」とは?便利な使い方も紹介!

投稿 2022年5月3日 最終更新 2022年5月3日 専門用語少なめ

Setとは?

Setとは、重複不可能なデータです。

Twitterのいいねみたいな、1投稿に1回しかいいねできない感じです。

実は内部的にはMapを使用しており、とても性質が似ています。

Setの種類

実はSetとはあくまで入れ物のようなもの(インターフェース)なだけで、
実際に動作する実物は以下の3種類あります。

HashSet

中身の順番は保持されません。

そのため、順番を保持しないといけないデータには、使用できません。

LinkedHashSet

追加した順番に保持されます。

TreeSet

キーによって、自動的に並び替えされます。

数字順・アルファベット順等の場合、
勝手に並び替えてくれるので便利です。

宣言する型について

一般的に下記のような宣言を見ることが多いかと思います。

Set<String, String> 変数名 = new HashSet<>();

このように、Setの中に実物を入れていることが多いと思います。

ただ同じ型に入れることももちろん可能です。

HashSet<String, String> 変数名 = new HashSet<>();

どう違うのかと言うと、使える機能が違います。

細かくいえば他にも違いはありますが、基本的にはSetのインターフェースに格納し、
必要に応じてインターフェースに無い機能を使いたい時だけHashSet等を使用するイメージで大丈夫だと思います。

そのため以下は全てSetに格納しております。

基本的な使い方

前提として、Setの中身のことは「要素」と呼びます。

初期化する

Setオブジェクトを初期化(生成)します。

基本的に引数は指定しなくてもいいですが、「初期容量」と「負荷係数」を指定できます。

指定しない場合、デフォルトで初期容量が16、負荷係数が0.75となります。

何かというと、オブジェクト生成時にまず、初期容量分の保存領域を確保します。

そして要素を追加していく中で、初期容量の負荷係数個に到達すると、保存領域を拡張します。

上記例でいうと、16個の領域があって、係数が0.75ということは、12個の要素を追加するときに、拡張します。

その後も負荷係数に達するたびに拡張し続けていきます。

この要領を拡張するという動作が非常に重たい動作になるので、できる限り最適に設定していきたいので、
最初からある程度量が分かっているのであれば、指定してあげるとパフォーマンスがよくなります。

import java.util.HashSet;
import java.util.Set;

public class SetTest {
  public static void main(String[] args) {
    // デフォルトの初期容量16とデフォルトの負荷係数0.75のインスタンスを生成
    Set<String> twitterGood1 = new HashSet<>();
    // 初期容量10とデフォルトの負荷係数0.75のインスタンスを生成
    Set<String> twitterGood2 = new HashSet<>(10);
    // 初期容量5と負荷係数1.0のインスタンスを生成
    Set<String> twitterGood3 = new HashSet<>(5, 1.0f);
  }
}

要素を追加する

シンプルに要素を追加していきます。

import java.util.HashSet;
import java.util.Set;

public class SetTest {
  public static void main(String[] args) {
    // インスタンスを生成
    Set<String> twitterGood = new HashSet<>();
    // 追加 [@sato]
    twitterGood.add("@sato");
    // 追加 [@sato, @suzuki]
    twitterGood.add("@suzuki");
    // 追加 [@sato, @suzuki, @tanaka]
    twitterGood.add("@tanaka");
  }
}

要素を削除する

要素が存在する時だけ、その要素を削除します。

import java.util.HashSet;
import java.util.Set;

public class SetTest {
  public static void main(String[] args) {
    // インスタンスを生成
    Set<String> twitterGood = new HashSet<>();
    // 追加 [@sato]
    twitterGood.add("@sato");
    // 追加 [@sato, @suzuki]
    twitterGood.add("@suzuki");
    // 追加 [@sato, @suzuki, @tanaka]
    twitterGood.add("@tanaka");
    // 一致する要素があれば削除
    // [@suzuki, @tanaka]
    twitterGood.remove("@sato");
  }
}

要素の数を取得する

Set内の要素の数を取得します。

取得できる数は人間が数える数字と同じなので、
1個、2個と数えるやり方と同じです。

import java.util.HashSet;
import java.util.Set;

public class SetTest {
  public static void main(String[] args) {
    // インスタンスを生成
    Set<String> twitterGood = new HashSet<>();
    // 中身の数を取得 > 0
    twitterGood.size();
    // 追加 [@sato]
    twitterGood.add("@sato");
    // 中身の数を取得 > 1
    twitterGood.size();
    // 追加 [@sato, @suzuki]
    twitterGood.add("@suzuki");
    // 中身の数を取得 > 2
    twitterGood.size();
  }
}

要素があるか判定する

Setに要素があるかどうかを判定します。

ただし完全一致しないと存在しないと判定されます。

import java.util.HashSet;
import java.util.Set;

public class SetTest {
  public static void main(String[] args) {
    // インスタンスを生成
    Set<String> twitterGood = new HashSet<>();
    // 追加 [@sato]
    twitterGood.add("@sato");
    // 追加 [@sato, @suzuki]
    twitterGood.add("@suzuki");
    // 追加 [@sato, @suzuki, @tanaka]
    twitterGood.add("@tanaka");
    // 存在するかを判定
    if (twitterGood.contains("@sato")) {
      // 今回は存在するのでtrue
    }
    // 存在しないかを判定
    if (!twitterGood.contains("sato")) {
      // 今回は完全一致しないのでtrue
    }
  }
}

便利な使い方

並び替え(ソート)する

上記で紹介した通り、並び替えを行うのであれば、TreeSetを使用します。

自動的に並び替えが行われます。

デフォルトは昇順のため、逆順に指定することで、降順に並び替えもできます。

ただ、自動のため少し特殊な並び替えは自分で実装しないといけません。

そういう場合は判定したうえで、LinkedHashSetに順に追加するのが楽でしょう。

import java.util.Collections;
import java.util.TreeSet;
import java.util.Set;

public class SetTest {
  public static void main(String[] args) {
    // インスタンスを生成
    Set<String> twitterGood = new TreeSet<>();
    // 追加 [@suzuki]
    twitterGood.add("@suzuki");
    // 追加 [@sato, @suzuki]
    twitterGood.add("@sato");
    // 追加 [@sato, @suzuki, @tanaka]
    twitterGood.add("@tanaka");
    // インスタンスを生成
    Set<String> twitterGoodReverse = new TreeSet<>(Collections.reverseOrder());
    // 追加 [@suzuki]
    twitterGoodReverse.add("@suzuki");
    // 追加 [@suzuki, @sato]
    twitterGoodReverse.add("@sato");
    // 追加 [@tanaka, @suzuki, @sato]
    twitterGoodReverse.add("@tanaka");
  }
}

要素すべてを出力する

実は1つを取得する機能が存在していないので、ループで取得します。

import java.util.HashSet;
import java.util.Set;

public class SetTest {
  public static void main(String[] args) {
    // インスタンスを生成
    Set<String> twitterGood = new HashSet<>();
    // 追加 [@suzuki]
    twitterGood.add("@suzuki");
    // 追加 [@sato, @sato]
    twitterGood.add("@sato");
    // 追加 [@sato, @suzuki, @tanaka]
    twitterGood.add("@tanaka");
    // ループですべて出力
    for (String good : twitterGood) {
      // 順に出力 > @sato, @suzuki, @tanaka
      System.out.println(good);
    }
  }
}

まとめ

Javaのコレクションの「Set」の紹介でした。

Setに限らずにJavaのコレクションを使いこなせれば、
楽に処理を実装できますし、わかりやすく書けますので、WinWinです。

使いこなせれば世界が変わるといっても過言ではないと思います!

以上、ここまで見ていただきありがとうございます。

皆さまの快適な開発ライフに、ほんの少しでもお役に立てれば幸いです。

コメント

この記事のコメントはありません。