特点: 元素无序,不可重复。包含以下几个常用的实现类:
Hashset
- 基于HashMap实现
- 线程不安全
- 元素无序,不依赖其添加至集合的顺序
- 允许null值
构造方法
默认方法为:
1
HashSet<E> nums = new HashSet<>();
也可以在构造时指定 容量(capacity) 和 负载因子(loadFactor):
1
Hashset<E> nums = new HashSet<>(8, 0.5);
这样创建的便是一个容量为8,负载因子为0.5的HashSet了。负载因子用于控制HashSet扩容的时机,例如这里为0.5代表着当HashSet被填充至总容量的50%时便会扩容,当前集合中的所有元素会转移到新的HashSet中。两个参数的默认值分别为16,0.75。
常用方法
方法 | 描述 |
---|---|
add(E e) | 添加指定元素 |
remove(E e) | 删除指定元素 |
addAll(Object o) | 求并集 |
retainAll(Object o) | 求交集 |
removeAll(Object o) | 求差集 |
containsAll(Object o) | 判断传入的集合是否为当前集合的子集 |
isEmpty() | 判断集合是否为空 |
size() | 返回集合中元素的个数 |
contains(E e) | 判断指定元素是否在当前集合中 |
clear() | 清空集合 |
代码示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
import java.util.*;
public class hashset{
public static void main(String[] args){
/* initialization */
HashSet<Integer> nums1 = new HashSet<>();
HashSet<Integer> nums2 = new HashSet<>();
HashSet<Integer> res = new HashSet<>();
Integer[] elements = {1, 9, 5, 6, 0, 2, 7, 3, 8, 4};
for (Integer e: elements){
nums1.add(e);
if (e % 2 == 0){
nums2.add(e);
}
}
print("nums1:", nums1);
print("nums2:", nums2);
System.out.println("");
/* add */
nums1.add(3);
nums2.add(3);
print("add 3 to nums1:", nums1);
print("add 3 to nums2:", nums2);
/* remove */
nums1.remove(4);
print("remove 4 from nums1:", nums1);
printBlank();
print("nums1:", nums1);
print("nums2:", nums2);
System.out.println("");
/* union */
res.addAll(nums1);
res.addAll(nums2);
print("nums1 | nums2:", res);
res.clear();
/* intersection */
res.addAll(nums1);
res.retainAll(nums2);
print("nums1 & nums2:", res);
res.clear();
/* difference */
res.addAll(nums1);
res.removeAll(nums2);
print("nums1 - nums2:", res);
res.clear();
printBlank();
/* isempty */
print("isempty:", res.isEmpty());
/* size */
print("nums1 size:", nums1.size());
/* contains */
print("nusm1 contains 12:", nums1.contains(12));
print("nums1 contains 1:", nums1.contains(1));
}
public static void print(String prompt, HashSet<Integer> nums){
System.out.println(String.format("%-25s %-30s", prompt, nums));
}
public static void print(String prompt, boolean res){
System.out.println(String.format("%-25s %-30s", prompt, res));
}
public static void print(String prompt, int num){
System.out.println(String.format("%-25s %-30s", prompt, num));
}
public static void printBlank(){
System.out.println("");
System.out.println("------------------");
System.out.println("");
}
}
输出:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
nums1: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
nums2: [0, 2, 4, 6, 8]
add 3 to nums1: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
add 3 to nums2: [0, 2, 3, 4, 6, 8]
remove 4 from nums1: [0, 1, 2, 3, 5, 6, 7, 8, 9]
------------------
nums1: [0, 1, 2, 3, 5, 6, 7, 8, 9]
nums2: [0, 2, 3, 4, 6, 8]
nums1 | nums2: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
nums1 & nums2: [0, 2, 3, 6, 8]
nums1 - nums2: [1, 5, 7, 9]
------------------
isempty: true
nums1 size: 9
nusm1 contains 12: false
nums1 contains 1: true
遍历方式
使用迭代器Iterator:
1
2
3
4
5
Iterator<Integer> iter = nums1.iterator();
System.out.print("iterate: ");
while (iter.hasNext()){
System.out.print(iter.next() + " ");
}
输出:
1
iterate: 0 1 2 3 5 6 7 8 9
关于无序性
在先前的叙述中我们反复提及了无序这个关键词,它的含义其实是:元素存入与取出的顺序不一致,并不是指依照元素的某些性质进行排序。验证Hashset无序性的示例代码如下所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import java.util.*;
public class hashset_iter {
public static void main(String[] args){
HashSet<Integer> nums1 = new HashSet<>();
HashSet<Integer> nums2 = new HashSet<>();
/* initialize nums1 */
nums1.add(1);
nums1.add(3);
nums1.add(2);
nums1.add(4);
/* initialize nums2 */
nums2.add(3);
nums2.add(4);
nums2.add(1);
nums2.add(2);
/* iterate nums1 */
Iterator<Integer> iter1 = nums1.iterator();
System.out.print("iterate nums1: ");
while (iter1.hasNext()){
System.out.print(iter1.next() + " ");
}
/* iterate nums2 */
Iterator<Integer> iter2 = nums2.iterator();
System.out.print("\niterate nums2: ");
while (iter2.hasNext()){
System.out.print(iter2.next() + " ");
}
}
}
输出:
1
2
iterate nums1: 1 2 3 4
iterate nums2: 1 2 3 4
可以看到,两个集合中元素的存入与取出的顺序并不一致。
LinkedHashSet
- 继承自HashSet,基于LinkedHashMap实现
- 元素有序,通过链表维护元素的顺序
- 线程不安全
- 与HashSet相比,增删元素时的性能稍逊,迭代访问元素时的性能稍好
- 允许null值
构造方法
与HashSet一致,同样包含容量与负载因子这两个参数。默认构造方法如下:
1
LinkedHashSet<E> nums = new LinkedHashSet<>();
常用方法
与HashSet一致。略。
遍历方式
依旧使用Iterator,略。
关于有序性
与HashSet那一节中提到的无序性定义一样,这里的有序指的是:元素存入与取出的顺序一致。示例代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import java.util.*;
public class linkedhashset_iter {
public static void main(String[] args){
/* initialization */
LinkedHashSet<Integer> nums1 = new LinkedHashSet<>();
Integer[] elements = {1, 3, 2, 4, 10, 6, 5};
for (Integer e: elements){
nums1.add(e);
}
/* iteration */
Iterator<Integer> iter = nums1.iterator();
System.out.print("iter: ");
while (iter.hasNext()){
System.out.print(iter.next() + " ");
}
}
}
输出:
1
iter: 1 3 2 4 10 6 5
可见,与HashSet不同,LinkedHashSet的元素存入与取出的顺序是一致的,这也验证了其的有序性。
TreeSet
- 是Set接口的子接口SortedSet的实现类
- 基于TreeMap实现
- 元素被排序,支持自然升序(默认) 与 自定义排序(Comparator)
- 性能比HashSet和LinkedHashSet差
- 线程不安全
- 不允许null值
构造方法
1
TreeSet<E> nums = new TreeSet<>();
此时集合中元素的排序方式为默认的升序排序。
常用方法
增删、迭代的方法与HashSet中的一致。除此之外独有的方法如下:
方法 | 描述 |
---|---|
first() | 返回集合的第一个元素 |
last() | 返回集合的最后一个元素 |
higher(E e) ceiling(E e) | 返回大于指定元素的最小元素,没有符合要求的元素会抛异常 返回大于等于指定元素的最小元素,没有符合要求的元素会抛异常 |
lower(E e) floor(E e) | 返回小于指定元素的最大元素,没有符合要求的元素会抛异常 返回小于等于指定元素的最大元素,没有符合要求的元素会抛异常 |
pollFirst() pollLast() | 返回并删除集合的第一个元素 返回并删除集合的最后一个元素 |
headSet(E e, boolean b) | 返回指定元素之前的所有元素,返回类型为SortedSet, 布尔值参数为 true 时包含边界,默认为false |
tailSet(E e, boolean b) | 返回指定元素之后的所有元素,返回类型为SortedSet, 布尔值参数为 true 时包含边界,默认为true |
subSet(E e1, boolean b1, E e2, boolean b2) | 返回两个指定元素之间的所有元素,返回类型为SortedSet, 布尔值参数为 true 时包含边界,b1默认为true ,b2默认为false |
代码示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
import java.util.*;
public class treeset {
public static void main(String[] args){
/* initialization */
TreeSet<Integer> nums = new TreeSet<>();
Integer[] elements = {1, 10, 4, 2, 3, 8, 7, 5, 9, 6};
for (Integer e: elements){
nums.add(e);
}
print("nums:", nums);
System.out.println("");
/* first */
print("first:", nums.first());
/* last */
print("last:", nums.last());
System.out.println("");
/* higher & ceiling*/
print("higher:", nums.higher(9));
print("ceiling:", nums.ceiling(9));
/* lower & floor */
print("lower:", nums.lower(9));
print("floor:", nums.floor(9));
System.out.println("");
/* poll */
print("pollfirst:", nums.pollFirst());
print("nums:", nums);
print("polllast:", nums.pollLast());
print("nums:", nums);
System.out.println("");
/* headset */
print("headset 5:", nums.headSet(5));
print("headset 5 true:", nums.headSet(5, true));
System.out.println("");
/* tailset */
print("tailset 6:", nums.tailSet(6));
print("tailset 6 false:", nums.tailSet(6, false));
System.out.println("");
/* subset */
print("subset 3 7:", nums.subSet(3, 7));
print("subset 3 false 7 false:", nums.subSet(3, false, 7, false));
print("subset 3 true 7 true:", nums.subSet(3, true, 7, true));
}
public static void print(String prompt, TreeSet<Integer> nums){
System.out.println(String.format("%-25s %-20s", prompt, nums));
}
public static void print(String prompt, int num){
System.out.println(String.format("%-25s %-20s", prompt, num));
}
public static void print(String prompt, SortedSet<Integer> nums){
System.out.println(String.format("%-25s %-20s", prompt, nums));
}
}
输出:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
nums: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
first: 1
last: 10
higher: 10
ceiling: 9
lower: 8
floor: 9
pollfirst: 1
nums: [2, 3, 4, 5, 6, 7, 8, 9, 10]
polllast: 10
nums: [2, 3, 4, 5, 6, 7, 8, 9]
headset 5: [2, 3, 4]
headset 5 true: [2, 3, 4, 5]
tailset 6: [6, 7, 8, 9]
tailset 6 false: [7, 8, 9]
subset 3 7: [3, 4, 5, 6]
subset 3 false 7 false: [4, 5, 6]
subset 3 true 7 true: [3, 4, 5, 6, 7]
自定义排序
想要自定义TreeSet中元素的排序方式,可以使用Comparator,具体代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import java.util.*;
public class treeset_comparator{
public static void main(String[] args){
TreeSet<Integer> nums = new TreeSet<>(new CustomComparator());
Integer[] elements = {1, 10, 3, 5, 6, 2, 4, 8, 7, 9};
for (Integer e: elements){
nums.add(e);
}
System.out.println(nums);
}
}
class CustomComparator implements Comparator<Integer>{
@Override
public int compare(Integer n1, Integer n2) {
return n2 - n1;
}
}
输出:
1
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
这里自定义的是降序排列的方式。