S-JIS[2014-07-05/2023-09-24] 変更履歴
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 |
true |
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 { 〜 } |
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 = 〜; |
UnmodifiableSortedSet |
1.2 | 不変SortedSet。 | SortedSet<String> set = 〜; |
|
UnmodifiableNavigableSet |
1.8 | 不変NavigableSet。 | NavigableSet<String> set = 〜; |
|
java.util. |
AbstractImmutableSet |
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); |
普通に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メソッドで複数の値を追加することが出来る。 |
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] |
Set関連の主なメソッド。
クラス | メソッド | JDK | 説明 | 例 | |
---|---|---|---|---|---|
コーディング | 結果 | ||||
java.util |
boolean add(E element) |
要素(値)を追加する。 既にその値を保持していた場合はfalseが返る。 |
Set<String> set1 = new LinkedHashSet<>(); |
[a, b, c] |
|
java.util |
void addFirst(E e) |
21 | 要素を先頭に追加する。(SequencedSetのみ) |
var set2 = new LinkedHashSet<>(set1); addFirst ("z"); |
[z, a, b, c] |
java.util |
void addLast(E e) |
21 | 要素を末尾に追加する。(SequencedSetのみ) |
var set2 = new LinkedHashSet<>(set1); addLast ("z"); |
[a, b, c, z] |
java.util |
boolean addAll(Collection<E> c) |
渡されたコレクションの全要素を自分のSetに追加する。 1つでも新たに追加されたらtrueが返る。 |
Set<String> set2 = new HashSet<>(set1); |
[a, b, c, x, y, z] |
|
java.util |
E getFirst() |
21 | 先頭の要素を取得する。(SequencedSetのみ) |
var set2 = new LinkedHashSet<>(set1); getFirst (); |
a |
java.util |
E getLast() |
21 | 末尾の要素を取得する。(SequencedSetのみ) |
var set2 = new LinkedHashSet<>(set1); Last (); |
c |
java.util |
void forEach( (T)
-> void action) |
1.8 |
全要素を順次処理する。 引数として、処理を行う関数を渡す。 |
set1.forEach(element -> System.out.println(element)); |
a |
java.util |
Iterator<E> iterator() |
Iteratorを返す。 |
for (Iterator<String> i = set1.iterator(); i.hasNext();) { |
a |
|
java.util |
Spliterator<E> spliterator() |
1.8 |
Streamに変換する際に使われる。 →stream() |
||
java.util |
int size() |
保持している要素の個数を返す。 |
int size = set1.size(); |
3 |
|
java.util |
boolean isEmpty() |
空Set(要素を保持していない)の場合、trueを返す。 |
boolean empty = set1.isEmpty(); |
false |
|
java.util |
boolean contains(Object element) |
指定された要素を保持している場合、trueを返す。 |
boolean exists = set1.contains("b"); |
true |
|
java.util |
boolean containsAll(Collection<?> c) |
渡されたコレクションに入っている全要素が自分のSet内に存在していたらtrueを返す。 |
Set<String> set = new HashSet<>(); |
true |
|
java.util |
void clear() |
全要素を削除する。 |
set2.clear(); |
[] |
|
java.util |
boolean remove(Object element) |
要素を削除する。 実際に削除した(要素を保持していた)場合はtrueが返る。 |
Set<String> set2 = new HashSet<>(set1); |
[a, c] |
|
java.util |
E removeFirst() |
21 | 先頭の要素を削除する。(SequencedSetのみ) |
var set2 = new LinkedHashSet<>(set1); removeFirst (); |
[b, c] |
java.util |
E removeLast() |
21 | 末尾の要素を削除する。(SequencedSetのみ) |
var set2 = new LinkedHashSet<>(set1); Last (); |
[a, b] |
java.util |
boolean removeAll(Collection<?> c) |
自分のSet内の各要素に対し、渡されたコレクションにその要素が含まれていたら、自分のSetからその要素を削除する。 1つでも削除した場合はtrueが返る。 |
Set<String> set = new HashSet<>(); |
[a] |
|
java.util |
boolean removeIf( (T) -> boolean filter) |
1.8 |
条件に合致する要素を削除する。 引数として、条件判定用の関数を渡す。 →Stream#filter()(Stream#filter()は、条件に一致するものを抽出する(残す)) |
Set<String> set2 = new HashSet<>(set1); |
[a, c] |
java.util |
boolean retainAll(Collection<?> c) |
自分のSet内の各要素に対し、渡されたコレクションにその要素が含まれていたら、その要素だけを残す(他の要素を削除する)。 1つでも削除した場合はtrueが返る。 |
Set<String> set = new HashSet<>(); |
[b, c] |
|
java.util |
SequencedSet<E>
reversed(E element) |
21 | 要素を逆順にしたSetを返す。(SequencedSetのみ) |
var set2 = new LinkedHashSet<>(set1); |
[c, b, a] |
java.util |
Object[] toArray() |
保持している全要素をObject配列にして返す。 |
Object[] array = set1.toArray(); |
[a, b, c] |
|
java.util |
T[] toArray(T[] array) |
保持している全要素を配列に入れて返す。 渡された配列に全要素が収まれば、その配列が返る。 渡された配列のサイズが小さい場合は拡張された配列が返る。 |
String[] array = set1.toArray(new String[set1.size()]); |
[a, b, c] |
|
java.util |
T[] toArray(IntFunction<T[]>) |
11 | 保持している全要素を配列に入れて返す。[2018-10-01] |
String[] array = set1.toArray(String[]::new); |
[a, b, c] |
java.util |
Stream<E> stream() |
1.8 | Stream(直列ストリーム)を返す。 |
Stream<String> stream = set1.stream(); |
|
java.util |
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メソッドを使い、ラムダ式で処理を記述する方法。 |
基本的には、処理される順序に保証は無い。
ただし、一部のクラス(LinkedHashSetやTreeSet・EnumSet等)では並び順が保証される。
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メソッドで作られるセットは不変セットである。[2017-09-24]
要素にnullを入れる事は出来ない。
不変セットなので、addやremove等の操作を行おうとするとUnsupportedOperationExceptionが発生する。
要素の並び順は不定。
Java9では、実体のクラスはImmutableCollectionsの内部クラスとして定義されている。
要素数が0個のときはSet0、1個のときはSet1、それ以外はSetNというクラスである。
SetNは、要素を保持するのに一次元配列だけを使用するので、メモリー使用効率はHashSetより良い。
(HashSetは、内部でHashMapを持っている)