Java Set 是一个不包含重复元素的集合。它继承于 Collection 接口。 它有以下特点:
Java Set 接口继承了 Collection 接口。 Collection 接口继承了 Iterable 接口。 一些常用的 Set 实现类有 HashSet,LinkedHashSet,TreeSet,CopyOnWriteArraySet 和 ConcurrentSkipListSet。AbstractSet 提供了 Set 接口的基本实现,以减少 Set 实现类的工作量。
Set 父接口:
Collection, Iterable
Set 子接口:
NavigableSet, SortedSet
Set 实现类:
AbstractSet, ConcurrentHashMap.KeySetView, ConcurrentSkipListSet, CopyOnWriteArraySet, EnumSet, HashSet, JobStateReasons, LinkedHashSet, TreeSet
方法 | 方法描述 |
---|---|
boolean add(E e) | 如果指定的元素不存在,则将其添加到此集合。如果此set已包含该元素,则保持set不变并返回false。 |
boolean addAll(Collection extends E> c) | 如果指定集合中的所有元素不存在当前集合中,则将其添加到此集合中。 否则,addAll操作会修改此集合,使其值为两个集合的并集。 如果操作正在进行时修改了指定的集合,则此操作的行为是不确定的。 |
void clear() | 清空当前结合中的所有元素 |
boolean contains(Object o) | 如果此set包含指定的元素,则返回true。当且仅当此集合包含元素e时才返回true(o == null?e == null:o.equals(e))。 |
boolean containsAll(Collection> c) | 如果此set包含指定collection的所有元素,则返回true。 如果指定的集合是当前集合的子集,则返回true。 |
boolean equals(Object o) | 将指定对象与此set进行相等性比较。 如果指定的对象也是一个集合,两个集合具有相同的大小,并且指定集合的每个成员都包含在此集合中,则返回true。 |
int hashCode() | 返回此set的哈希码值。 集合的哈希码被定义为集合中元素的哈希码的总和,其中空元素的哈希码被定义为零。 这意味着对于任何两个集合s1和s2的 s1.hashCode()== s2.hashCode()时,s1.equals(s2)。 |
boolean isEmpty() | 如果此set不包含任何元素,则返回true。 |
Iterator iterator() | 返回此set中元素的迭代器。 元素以无特定顺序返回 |
boolean remove(Object o) | 从该集合中移除指定的元素,如果该元素存在集合中,则返回true |
boolean removeAll(Collection> c) | 从当前集合中删除所有包含指定集合的元素 |
boolean retainAll(Collection> c) | 仅保留当前集合中包含指定集合中的元素。 换句话说,该方法最终结果为两个集合的交集。 |
int size() | 返回此集合中的元素数。 如果此set包含 Integer.MAX_VALUE 个元素,则返回 Integer.MAX_VALUE。 |
default Spliterator spliterator() | 在此集合中的元素上创建Spliterator |
Object[] toArray() | 返回包含此set中所有元素的数组。 返回的数组将是“安全的”,因为该集合不维护对它的引用。 (换句话说,即使此数组由数组支持,此方法也必须分配一个新数组)。 因此调用者可以自由修改返回的数组。 |
T[] toArray(T[] a) | 返回一个包含此set中所有元素的数组; 返回数组的运行时类型是指定数组的运行时类型。 如果集合适合指定的数组,则返回指定类型的数组。 否则,将使用指定数组的运行时类型和此set的大小分配新数组。如果此set适合指定的数组,并且有空余空间(即,数组的元素多于此set),则紧跟在该set结尾之后的数组中的元素将设置为null。 |
从接口 java.util.Collection 继承的方法有:
parallelStream, removeIf, stream
从接口 java.lang.Iterable 继承的方法有:
forEach
与List不同,我们不能直接将Java Set转换为数组,因为它不是使用Array实现的。因此我们不能直接使用 Arrays 将数组转换为 Set 。 但是,我们可以采用另一种方法,我们可以使用Arrays.asList()方法将数组转换为List,然后使用它来创建Set。
通过使用这种方法,我们可以通过两种方式将Java数组转换为Set。 下面让我们用一个简单例子,分别演示以下这两种方式。
在这种方法中,首先我们需要使用给定的数组创建一个List,然后使用它来创建一个Set,如下所示。
public static void main(String[] args) {
String[] vowels = {"h", "e", "l", "l", "o"};
Set vowelsSet = new HashSet(Arrays.asList(vowels));
System.out.println(vowelsSet);
}
在这种方法中,我们不使用 List 来作为从Array 转换为 Set 的中间集合。 首先创建一个空的 HashSet,然后使用 Collections.addAll()将数组元素复制到给定的 Set 中,如下所示。
public static void main(String[] args) {
String[] vowels = {"h", "e", "l", "l", "o"};
Set vowelsSet = new HashSet<>();
Collections.addAll(vowelsSet, vowels);
System.out.println(vowelsSet);
}
接下来我们将使用 Set.toArray()方法将一组字符串转换为字符串数组,如下所示。
public static void main(String[] args) {
Set vowelsSet = new HashSet<>();
vowelsSet.add("h");
vowelsSet.add("e");
vowelsSet.add("l");
vowelsSet.add("l");
vowelsSet.add("o");
//将 set 转换为 array
String strArray[] = vowelsSet.toArray(new String[vowelsSet.size()]);
System.out.println(Arrays.toString(strArray));
}
我们知道,Set(HashSet)不支持直接对元素排序。 它以随机顺序存储和显示元素。但是,我们有一些方法可以对它的元素进行排序,如下所示:
public static void main(String[] args) {
Set intsSet = new HashSet<>();
Random random = new Random();
for (int i = 0; i < 10; i++) {
intsSet.add(random.nextInt(1000));
}
System.out.println("无序Set: " + intsSet);
Set sortedSet = new TreeSet<>(intsSet);
System.out.println("有序Set: " + sortedSet);
}
输出结果:
无序Set: [64, 882, 18, 468, 500, 741, 636, 668, 654, 670]
有序Set: [18, 64, 468, 500, 636, 654, 668, 670, 741, 882]
下面是一个示例,说明如何将Java Set转换为Stream并根据我们的要求执行某些操作。
public static void main(String[] args) {
Set vowelsSet = new HashSet<>();
vowelsSet.add("h");
vowelsSet.add("e");
vowelsSet.add("l");
vowelsSet.add("l");
vowelsSet.add("o");
//转换 set 为 stream 并进行遍历输出
vowelsSet.stream().forEach(System.out::println);
}
输出结果:
e
h
l
o
在Java Set上我们最常用的操作是add,addAll,clear,size等。下面是一个简单的Java Set 示例,显示了常用的方法用法。
public static void main(String args[]) {
Set vowels = new HashSet<>();
//add
vowels.add("H");
vowels.add("E");
vowels.add("L");
System.out.println("vowels:" + Arrays.toString(vowels.toArray()));
Set set = new HashSet<>();
set.add("O");
set.add("U");
//将集合Set 中的元素全部添加到集合 vowels 中
vowels.addAll(set);
System.out.println("vowels.addAll(set):" + Arrays.toString(vowels.toArray()));
//清空set
set.clear();
//set size
System.out.println("vowels size : " + vowels.size());
vowels.clear();
vowels.add("E");
vowels.add("E");
vowels.add("I");
vowels.add("O");
System.out.println("判断集合 vowels 中是否包含 E = " + vowels.contains("E"));
}
输出结果:
vowels:[E, H, L]
vowels.addAll(set):[E, U, H, L, O]
vowels size : 5
判断集合 vowels 中是否包含 E = true
下面是一个例子,展示了如何迭代Java Set。
public static void main(String[] args) {
Set set = new HashSet<>();
for (int i = 0; i < 5; i++) {
set.add(i);
}
//获取迭代器
Iterator iterator = set.iterator();
//简单迭代
System.out.println("迭代集合元素:");
while (iterator.hasNext()) {
int i = (int) iterator.next();
System.out.print(i + " ");
}
//使用迭代器修改 set 元素
iterator = set.iterator();
while (iterator.hasNext()) {
int x = (int) iterator.next();
if (x % 2 == 0) {
iterator.remove();
}
}
System.out.println();
System.out.println("使用迭代器修改set元素以后:" + set);
//迭代时改变set结构
iterator = set.iterator();
System.out.println("迭代时改变set结构,ConcurrentModificationException:" + set);
while (iterator.hasNext()) {
//ConcurrentModificationException
int x = (int) iterator.next();
if (x == 1) {
set.add(10);
}
}
}
输出结果:
迭代集合元素:
0 1 2 3 4
使用迭代器修改set元素以后:[1, 3]
迭代时改变set结构,ConcurrentModificationException:
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.HashMap$HashIterator.nextNode(HashMap.java:1442)
at java.util.HashMap$KeyIterator.next(HashMap.java:1466)
at com.lkf.collection.map.SetIteratorExample.main(SetIteratorExample.java:48)