S-JIS[2014-07-05/2023-09-24] 変更履歴

java.util.Set

Javaコレクションのひとつであるセット(集合)について。


概要

セットは、値が存在しているかどうかを保持するのに適したコレクション。いわゆる集合。
同じ値(要素)を複数保持する事が出来ない。
並び順も基本的には保持されない。(並び順を保持するSetもある)

Listは同一の値(要素)を複数保持し、並び順も保証される。


セットは、java.util.Setインターフェースで表される。

SetはIterableインターフェースを継承しているので、for each構文で使うことが出来る。

SetのサブインターフェースとしてSortedSet(並び順が保持されるSet)があり、さらにその下にNavigableSetがある。
SortedSet(NavigableSet)の代表例はTreeSet


Setは、いわば「Map<型, Boolean>」と同等。
つまり、「キーが要素、値が存在有無(boolean)のMap」と同等だと考えることが出来る。

  Setの例 Mapの例
生成
Set<String> set = new HashSet<>();
Map<String, Boolean> map = new HashMap<>();
追加
削除
set.add("a");
set.add("b");
set.add("c");
set.remove("b");
map.put("a", true);
map.put("b", true);
map.put("c", true);
map.put("b", false);
取得
System.out.println(set.contains("a"));
System.out.println(set.contains("b"));
System.out.println(map.get("a"));
System.out.println(map.get("b"));
出力結果 true
false
true
false

セットの具象クラス

Setの主な具象クラス。

クラス名 JDK 説明 インスタンスを生成する例
java.util HashSet 1.2 値のハッシュ値を使って探索するSet。
コンストラクターで初期サイズを指定可能。
Set<String> set = new HashSet<String>(10);
// Java19 [2022-09-21]
Set<String> set = HashSet.newHashSet(10);
java.util LinkedHashSet 1.4 並び順(追加した順序)が保持されるHashSet。 Set<String> set = new LinkedHashSet<String>(10);
// Java19 [2022-09-21]
Set<String> set = LinkedHashSet.newLinkedHashSet(10);
java.util TreeSet 1.2 値の大小順で並ぶSet。(NavigableSet) Set<String> set = new TreeSet<String>();
java.util EnumSet 1.5 列挙値を保持するSet。
EnumSetの使用例
enum MyEnum { 〜 }
Set<MyEnum> set = EnumSet.noneOf(MyEnum.class);
java.util.Collections EmptySet 1.2 空の不変Set。 Set set = Collections.EMPTY_SET; // JDK1.4
Set<String> set = Collections.emptySet();
EmptyNavigableSet 1.8 空の不変NavigableSet(SortedSet)。 SortedSet<String> set = Collections.emptySortedSet();
NavigableSet<String> set = Collections.emptyNavigableSet();
java.util.Collections SingletonSet 1.2 要素が1つの不変Set。 Set<String> set = Collections.singleton("a");
java.util.Collections UnmodifiableSet 1.2 不変Set。 Set<String> set = 〜;
Set<String> uset = Collections.unmodifiableSet(set);
UnmodifiableSortedSet 1.2 不変SortedSet。 SortedSet<String> set = 〜;
SortedSet<String> uset = Collections.unmodifiableSortedSet(set);
UnmodifiableNavigableSet 1.8 不変NavigableSet。 NavigableSet<String> set = 〜;
NavigableSet<String> uset = Collections.unmodifiableNavigableSet(set);
java.util.
ImmutableCollections
AbstractImmutableSet
List0, List1, ListN
9 不変Set[2018-06-02]
Set.ofメソッドで返されるSet。
Set<String> set = Set.of("a", "b");
java.util.Collections CheckedSet 1.5 動的型保証されるSet。
不正な型の値(要素)を入れたらClassCastExceptionを発生させてくれる。
 
CheckedSortedSet 1.5 動的型保証されるSortedSet。  
CheckedNavigableSet 1.8 動的型保証されるNavigableSet。  
java.util.Collections SynchronizedSet 1.2 同期化(synchronized)されるSet。  
SynchronizedSortedSet 1.2 同期化(synchronized)されるSortedSet。  
SynchronizedNavigableSet 1.8 同期化(synchronized)されるNavigableSet。  
java.util.concurrent CopyOnWriteArraySet 1.5 マルチスレッドセーフなSet。
MTセーフなコレクション
 

java.util.BitSetはビット群を保持するクラスで、「Set」という名前が付いているが、Setの具象クラスではない。
BitSetの説明


セットの初期化

配列だと初期値を列挙する初期化構文がある(ScalaのSetにも初期値を指定する方法がある)が、JavaのSetでは構文としては用意されていない。

方法 JDK 説明
通常   Set<String> set = new HashSet<>(10);
set.add("a");
set.add("b");
set.add("c");
普通にaddする方法。
asList 1.5 Set<String> set = new HashSet<>(Arrays.asList("a", "b", "c")); Arrays.asListメソッド(List)を経由して初期化する方法。
addAll 1.5 Set<String> set = new HashSet<>();
Collections.addAll(set, "a", "b", "c");
Collections.addAllメソッドで複数の値を追加することが出来る。
EnumSet 1.5 Set<MyEnum> set = EnumSet.of(MyEnum.A, MyEnum.B, MyEnum.C); EnumSetの場合は、ofメソッドで初期化できる。[2014-11-22]
初期化子   Set<String> set = new HashSet<String>() {{ add("a");add("b");add("c"); }}; インスタンス初期化子を使う方法。
実務的には使用すべきではないだろう。
Stream 1.8 Set<String> set = Stream.of("a", "b", "c").collect(Collectors.toSet()); Streamを使う方法。
of 9 Set<String> set = Set.of("a", "b", "c"); Set.ofメソッドは不変セットを返す。[2017-09-24]
要素にnullを指定するとNullPointerExceptionが発生する。
また、要素が重複しているとIllegalArgumentExceptionが発生する。
他のコレクション
から作る場合
  Set<String> set2 = new HashSet<>(set);  
10 Set<String> set2 = Set.copyOf(set); Set.copyOfメソッドは不変セットを返す。[2018-06-02]

EnumSetの初期化方法


セットのメソッド

Set関連の主なメソッド。

クラス メソッド JDK 説明
コーディング 結果
java.util
Collection<E>
 
boolean add(E element)   要素(値)を追加する。
既にその値を保持していた場合はfalseが返る。
Set<String> set1 = new LinkedHashSet<>();
set1.add("a");
set1.add("b");
set1.add("c");
[a, b, c]
java.util
SequencedSet<E>
void addFirst(E e) 21 要素を先頭に追加する。(SequencedSetのみ) var set2 = new LinkedHashSet<>(set1);
set2.
addFirst("z");
[z, a, b, c]
java.util
SequencedSet<E>
void addLast(E e) 21 要素を末尾に追加する。(SequencedSetのみ) var set2 = new LinkedHashSet<>(set1);
set2.
addLast("z");
[a, b, c, z]
java.util
Collection<E>
boolean addAll(Collection<E> c)   渡されたコレクションの全要素を自分のSetに追加する。
1つでも新たに追加されたらtrueが返る。
Set<String> set2 = new HashSet<>(set1);
set2.addAll(Arrays.asList("x", "y", "z"));
[a, b, c, x, y, z]
java.util
SequencedSet<E>
E getFirst() 21 先頭の要素を取得する。(SequencedSetのみ) var set2 = new LinkedHashSet<>(set1);
set2.
getFirst();
a
java.util
SequencedSet<E>
E getLast() 21 末尾の要素を取得する。(SequencedSetのみ) var set2 = new LinkedHashSet<>(set1);
set2.get
Last();
c
java.util
Iterable<E>
void forEach((T) -> void action) 1.8 全要素を順次処理する。
引数として、処理を行う関数を渡す。
set1.forEach(element -> System.out.println(element)); a
b
c
java.util
Iterable<E>
Iterator<E> iterator()   Iteratorを返す。 for (Iterator<String> i = set1.iterator(); i.hasNext();) {
  String element = i.next();
  System.out.println(element);
}
a
b
c
java.util
Iterable<E>
Spliterator<E> spliterator() 1.8 Streamに変換する際に使われる。
stream()
   
java.util
Collection<E>
int size()   保持している要素の個数を返す。 int size = set1.size(); 3
java.util
Collection<E>
boolean isEmpty()   空Set(要素を保持していない)の場合、trueを返す。 boolean empty = set1.isEmpty(); false
java.util
Collection<E>
boolean contains(Object element)   指定された要素を保持している場合、trueを返す。 boolean exists = set1.contains("b"); true
java.util
Collection<E>
boolean containsAll(Collection<?> c)   渡されたコレクションに入っている全要素が自分のSet内に存在していたらtrueを返す。 Set<String> set = new HashSet<>();
Collections.addAll(set, "b","c");
boolean exists = set1.containsAll(set);
true
java.util
Collection<E>
void clear()   全要素を削除する。 set2.clear(); []
java.util
Collection<E>
boolean remove(Object element)   要素を削除する。
実際に削除した(要素を保持していた)場合はtrueが返る。
Set<String> set2 = new HashSet<>(set1);
set2.remove("b");
[a, c]
java.util
SequencedSet<E>
E removeFirst() 21 先頭の要素を削除する。(SequencedSetのみ) var set2 = new LinkedHashSet<>(set1);
set2.
removeFirst();
[b, c]
java.util
SequencedSet<E>
E removeLast() 21 末尾の要素を削除する。(SequencedSetのみ) var set2 = new LinkedHashSet<>(set1);
set2.remove
Last();
[a, b]
java.util
Collection<E>
boolean removeAll(Collection<?> c)   自分のSet内の各要素に対し、渡されたコレクションにその要素が含まれていたら、自分のSetからその要素を削除する。
1つでも削除した場合はtrueが返る。
Set<String> set = new HashSet<>();
Collections.addAll(set, "b", "c", "d");
Set<String> set2 = new HashSet<>(set1);
set2.removeAll(set);
[a]
java.util
Collection<E>
boolean removeIf((T) -> boolean filter) 1.8 条件に合致する要素を削除する。
引数として、条件判定用の関数を渡す。
Stream#filter()(Stream#filter()は、条件に一致するものを抽出する(残す))
Set<String> set2 = new HashSet<>(set1);
set2.removeIf(element -> element.equals("b"));
[a, c]
java.util
Collection<E>
boolean retainAll(Collection<?> c)   自分のSet内の各要素に対し、渡されたコレクションにその要素が含まれていたら、その要素だけを残す(他の要素を削除する)。
1つでも削除した場合はtrueが返る。
Set<String> set = new HashSet<>();
Collections.addAll(set, "b", "c", "d");
Set<String> set2 = new HashSet<>(set1);
set2.retainAll(set);
[b, c]
java.util
SequencedSet<E>
SequencedSet<E> reversed(E element) 21 要素を逆順にしたSetを返す。(SequencedSetのみ) var set2 = new LinkedHashSet<>(set1);
var set3 = set2.reversed();
[c, b, a]
java.util
Collection<E>
Object[] toArray()   保持している全要素をObject配列にして返す。 Object[] array = set1.toArray(); [a, b, c]
java.util
Collection<E>
T[] toArray(T[] array)   保持している全要素を配列に入れて返す。
渡された配列に全要素が収まれば、その配列が返る。
渡された配列のサイズが小さい場合は拡張された配列が返る。
String[] array = set1.toArray(new String[set1.size()]); [a, b, c]
java.util
Collection<E>
T[] toArray(IntFunction<T[]>) 11 保持している全要素を配列に入れて返す。[2018-10-01] String[] array = set1.toArray(String[]::new); [a, b, c]
java.util
Collection<E>
Stream<E> stream() 1.8 Stream(直列ストリーム)を返す。 Stream<String> stream = set1.stream();  
java.util
Collection<E>
Stream<E> parallelStream() 1.8 Stream(並列ストリーム)を返す。 Stream<String> stream = set1.parallelStream();  

クラスやメソッドによっては、java.lang.UnsupportedOperationExceptionを返す実装もある。
例えばUnmodifiableSetは不変セットなので、値を変更するaddやremoveメソッドを呼び出すとUnsupportedOperationExceptionが発生する。


順次アクセス操作

Setでは、保持している値(要素)を順次処理していくことが出来る。

Iteratorパターン JDK1.4
for (Iterator i = set.iterator(); i.hasNext();) {
	型 変数 = (型) i.next();
〜
}
 
JDK1.5
for (Iterator<型> i = set.iterator(); i.hasNext();) {
	型 変数 = i.next();
〜
}
JDK1.5ではジェネリクスが使えるようになった。
for each構文 JDK1.5
for (型 変数 : set) {
〜
}
SetはIterableを継承しているので、for each構文を使うことが出来る。
forEachメソッド JDK1.8
set.forEach(変数 -> {
〜
});
forEachメソッドを使い、ラムダ式で処理を記述する方法。

基本的には、処理される順序に保証は無い。
ただし、一部のクラス(LinkedHashSetTreeSetEnumSet等)では並び順が保証される。


Streamとの変換

SetからStreamを生成するにはstreamもしくはparallelStreamメソッドを使用する。

	Set<String> set = new HashSet<>();
	set.add("abc");
	set.add("def");

	Stream<String> stream = set.stream();

StreamからSetを生成するにはCollectors.toSetを使用する。

	Stream<String> stream = Stream.of("abc", "def");

	Set<String> set = stream.collect(Collectors.toSet());

Collectors.toListの内部は、java.util.HashSetを作成して、Stream内の要素をaddしていく形になっている。

HashSet以外のSetにしたい場合は以下のようにする。

	Set<String> set = stream.collect(LinkedHashSet::new, Set::add, (left, right) -> left.addAll(right));

Set.ofの不変セット

Set.ofメソッドで作られるセットは不変セットである。[2017-09-24]
要素にnullを入れる事は出来ない。
不変セットなので、addやremove等の操作を行おうとするとUnsupportedOperationExceptionが発生する。
要素の並び順は不定。

Java9では、実体のクラスはImmutableCollectionsの内部クラスとして定義されている。
要素数が0個のときはSet0、1個のときはSet1、それ以外はSetNというクラスである。

SetNは、要素を保持するのに一次元配列だけを使用するので、メモリー使用効率はHashSetより良い。
(HashSetは、内部でHashMapを持っている)


コレクションへ戻る / Java目次へ戻る / 新機能へ戻る / 技術メモへ戻る
メールの送信先:ひしだま