集合

SET1

单列集合

Collection-struct

红色:接口

蓝色:实现类

Collection

双列集合

map

数据结构

datastructure

stack1

stack2

队列

queue1

queue2

数组

array

链表

linklist1

linklist2

linklist3

datastructure-summary

二叉树

tree1

二叉查找树

tree2

添加节点:

  • 小的存左边
  • 大的存右边
  • 一样的不存

遍历方式:

  1. 前序遍历
  2. 中序遍历
  3. 后序遍历
  4. 层序遍历

tree3

弊端:长短腿 -> 解决方案:平衡二叉树

平衡二叉树

tree5

tree6

旋转机制

规则:

  1. 左旋
  2. 右旋

触发时机:当添加一个节点之后,该树不再是一颗平衡二叉树

左旋:

tree7

tree8

右旋:

tree9

tree10

需要旋转的四种情况:

  1. 左左:一次右旋(当根节点左子树的左子树有节点插入,导致二叉树不平衡。下面同上)
  2. 左右:先局部左旋,再整体右旋
  3. 右右:一次左旋
  4. 右左:先局部右旋,再整体左旋

红黑树

数据结构:

tree11

红黑规则:

tree12

添加规则:

tree13

泛型

pattern1

pattern2

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.ArrayList;
import java.util.Iterator;

public class Main {
public static void main(String[] args) {
//没有泛型的时候,集合如何存储数据
//结论:
//如果我们没有给集合指定类型,默认认为所有的数据类型都是Object类型
//此时可以往集合添加任意的数据类型
//带来一个坏处:我们在获取数据的时候,无法使用他的特有行为。

//此时推出了泛型,可以在添加数据的时候就把类型进行统一
//而且我们在获取数据的时候,也省的强转了,非常的方便

//1.创建集合的对象
ArrayList<String> list = new ArrayList<>();

//2.添加数据
//list.add(123);
list.add("aaa");
//list.add(new Student("ZhangSan", 18));

//3.遍历集合获取里面的每一个元素
Iterator<String> it = list.iterator();
while (it.hasNext()) {
String str = it.next();
//多态的弊端是不能访问子类的特有功能
//obj.length();
//str.length();
System.out.println(str);
}

}
}

pattern3

pattern4

泛型类

pattern-class1

pattern-class2

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
import java.util.Arrays;

public class Main {
public static void main(String[] args) {
MyArrayList<String> list1 = new MyArrayList<>();
list1.add("A");
list1.add("B");
list1.add("C");

System.out.println(list1);

MyArrayList<Integer> list2 = new MyArrayList<>();
list2.add(1);
list2.add(2);
list2.add(3);

int i = list2.get(0);
System.out.println(i);

System.out.println(list2);
}
}


/*
当我在编写一个类的时候,如果不确定类型,那么这个类就可以定义为泛型类
*/
class MyArrayList<E> {
Object[] obj = new Object[10];
int size;

/*
E: 表示不确定的类型,该类型在类后面已经定义过了
e: 形参的名字,变量名
*/
public boolean add(E e) {
obj[size] = e;
size++;
return true;
}

public E get(int index) {
return (E) obj[index];
}

@Override
public String toString() {
return Arrays.toString(obj);
}
}

泛型方法

pattern-method1

patterm-method2

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
import java.util.ArrayList;

public class Main {
public static void main(String[] args) {
ArrayList<String> list1 = new ArrayList<>();
ListUtil.add_All(list1, "aaa", "bbb", "ccc", "ddd", "eee");
System.out.println(list1);

ArrayList<Integer> list2 = new ArrayList<>();
ListUtil.add_All(list2, 1, 2, 3, 4, 5, 6, 7, 8, 9);
System.out.println(list2);
}
}
class ListUtil {
private ListUtil() {}

//类中定义一个静态方法addAll,用来添加多个集合的元素

/*
参数一:集合
参数二~最后:要添加的元素
*/

public static<E> void add_All(ArrayList<E> list, E...e) {
for (E element : e) {
list.add(element);
}
}
}

泛型接口

pattern-interface

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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;

public class Main {
public static void main(String[] args) {
/*
泛型接口的两种使用方式:
1.实现类给出具体的类型
2.实现类延续泛型,创建实现类对象时再确定类型
*/

MyArrayList1 list1 = new MyArrayList1();
list1.add("aaa");

MyArrayList2<String> list2 = new MyArrayList2<>();
list2.add("bbb");
}
}
class MyArrayList1 implements List<String> {
@Override
public int size() {
return 0;
}

@Override
public boolean isEmpty() {
return false;
}

@Override
public boolean contains(Object o) {
return false;
}

@Override
public Iterator<String> iterator() {
return null;
}

@Override
public Object[] toArray() {
return new Object[0];
}

@Override
public <T> T[] toArray(T[] a) {
return null;
}

@Override
public boolean add(String s) {
return false;
}

@Override
public boolean remove(Object o) {
return false;
}

@Override
public boolean containsAll(Collection<?> c) {
return false;
}

@Override
public boolean addAll(Collection<? extends String> c) {
return false;
}

@Override
public boolean addAll(int index, Collection<? extends String> c) {
return false;
}

@Override
public boolean removeAll(Collection<?> c) {
return false;
}

@Override
public boolean retainAll(Collection<?> c) {
return false;
}

@Override
public void clear() {

}

@Override
public String get(int index) {
return "";
}

@Override
public String set(int index, String element) {
return "";
}

@Override
public void add(int index, String element) {

}

@Override
public String remove(int index) {
return "";
}

@Override
public int indexOf(Object o) {
return 0;
}

@Override
public int lastIndexOf(Object o) {
return 0;
}

@Override
public ListIterator<String> listIterator() {
return null;
}

@Override
public ListIterator<String> listIterator(int index) {
return null;
}

@Override
public List<String> subList(int fromIndex, int toIndex) {
return List.of();
}
}

class MyArrayList2<E> implements List<E> {
@Override
public int size() {
return 0;
}

@Override
public boolean isEmpty() {
return false;
}

@Override
public boolean contains(Object o) {
return false;
}

@Override
public Iterator<E> iterator() {
return null;
}

@Override
public Object[] toArray() {
return new Object[0];
}

@Override
public <T> T[] toArray(T[] a) {
return null;
}

@Override
public boolean add(E e) {
return false;
}

@Override
public boolean remove(Object o) {
return false;
}

@Override
public boolean containsAll(Collection<?> c) {
return false;
}

@Override
public boolean addAll(Collection<? extends E> c) {
return false;
}

@Override
public boolean addAll(int index, Collection<? extends E> c) {
return false;
}

@Override
public boolean removeAll(Collection<?> c) {
return false;
}

@Override
public boolean retainAll(Collection<?> c) {
return false;
}

@Override
public void clear() {

}

@Override
public E get(int index) {
return null;
}

@Override
public E set(int index, E element) {
return null;
}

@Override
public void add(int index, E element) {

}

@Override
public E remove(int index) {
return null;
}

@Override
public int indexOf(Object o) {
return 0;
}

@Override
public int lastIndexOf(Object o) {
return 0;
}

@Override
public ListIterator<E> listIterator() {
return null;
}

@Override
public ListIterator<E> listIterator(int index) {
return null;
}

@Override
public List<E> subList(int fromIndex, int toIndex) {
return List.of();
}
}

通配符

泛型的继承和通配符:

  • 泛型不具备继承性,但是数据具备继承性
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
import java.util.ArrayList;

public class Main {
public static void main(String[] args) {
/*
泛型不具备继承性,但是数据具备继承性
*/

//创建集合的对象
ArrayList<Ye> list1 = new ArrayList<>();
ArrayList<Fu> list2 = new ArrayList<>();
ArrayList<Zi> list3 = new ArrayList<>();

//调用method方法
method1(list1);
// method(list2);
// method(list3);

list1.add(new Ye());
list1.add(new Fu());
list1.add(new Zi());

method3(list1);
method2(list2);
method3(list3);

method4(list1);
method4(list2);
method4(list3);
/*
需求:
定义一个方法,形参是一个集合,但是集合中的数据类型不确定
*/
}

/*
此时,泛型里面写的是什么类型,那么只能传递什么类型的数据
*/
public static void method1(ArrayList<Ye> list) {}

/*
此时,泛型里面写的是什么类型,那么只能传递什么类型的数据
弊端:
利用泛型方法有一个小弊端,此时他可以接受任意的数据类型
Ye Fu Zi Student

希望:本方法虽然不确定数据类型,但是以后我希望只能传递Ye Fu Zi

此时可以使用泛型的通配符:
? 表示不确定的类型
他可以进行类型的限定
? extends E: 表示可以传递E或者E的所有子类类型
? super E: 表示可以传递E或者E的所有父类类型

应用场景:
1.如果我们在定义类、方法、接口的时候,如果类型不确定,就可以定义泛型类、泛型方法、泛型接口
2.如果类型不确定。但是能知道以后只能传递某个继承体系中的,就可以泛型的通配符
泛型的通配符:
关键点:可以限定类型的范围
*/
public static<E> void method2(ArrayList<E> list) {}

public static void method3(ArrayList<? extends Ye> list) {}

public static void method4(ArrayList<? super Zi> list) {}
}
class Ye{}
class Fu extends Ye{}
class Zi extends Fu{}

pattern5

pattern6

Collection

方法

Collection1

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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
import java.util.ArrayList;
import java.util.Collection;
import java.util.Objects;

public class Main {
public static void main(String[] args) {
/*
public boolean add(E e) 添加
public void clear() 清空
pubic boolean remove(E e) 删除
public boolean contains(Object obj) 判断是否包含
public boolean isEmpty() 判断是否为空
public int size() 集合长度

注意点:
Collection是一个接口,我们不能直接创建他的对象
所以:现在我们学习他的方法时,只能创建实现类的对象
实现类:ArrayList ...
*/

//目的:为了学习Collection接口里面的方法
//自己在做一些练习的时候,还是按照之前的方式去创建对象
//多态方式创建对象:
Collection<String> coll = new ArrayList<>();

//1.添加元素
//细节1:如果我们要往List系列集合中添加元素,那么方法永远返回true,因为List系列是匀许元素重复的
//细节2:如果我们要往Set系列集合中添加数据,如果当前要添加元素不存在,方法返回true,表示添加成功
// 如果当前要添加的元素已经存在,方法返回false,表示添加失败
// 因为Set系列的集合不允许重复
coll.add("aaa");
coll.add("bbb");
coll.add("ccc");
System.out.println(coll);

//2.清空
//coll.clear();

//3.删除
//细节1:因为Collection里面定义的是共性的方法,所以此时不能通过索引进行删除,只能通过元素的对象进行删除
//细节2:方法会有一个布尔类型的返回值,删除成功返回true,删除失败返回false
//如果要删除的元素不存在,就会删除失败
coll.remove("bbb");
System.out.println(coll);

//4.判断元素是否包含
//细节:底层是依赖equals方法进行判断是否存在的
//所以,如果集合中存储的是自定义对象,也想通过contains方法来判断是否包含,那么在javabean类中一定要重写equals方法
boolean result = coll.contains("ccc");
System.out.println(result);

//5.判断集合是否为空
boolean result2 = coll.isEmpty();
System.out.println(result2);

//6.获取集合的长度
int size = coll.size();
System.out.println(size);

Collection<Student> coll2 = new ArrayList<>();

Student s1 = new Student("ZhangSan", 18);
Student s2 = new Student("LiSi", 20);
Student s3 = new Student("WangWu", 22);

coll2.add(s1);
coll2.add(s2);
coll2.add(s3);

//如果存储的是自定义对象,那么默认使用Object类中的equals方法进行判断,而Object类中的equals方法,依赖地址值进行判断
//如果同名同年龄。认为是同一个学生
//需要在自定义的Javabean类中,重写equals方法
Student s4 = new Student("ZhangSan", 18);
System.out.println(coll2.contains(s4));
}
}

class Student {
private String name;
private int age;

public Student() {
}

public Student(String name, int age) {
this.name = name;
this.age = age;
}

/**
* 获取
* @return name
*/
public String getName() {
return name;
}

/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}

/**
* 获取
* @return age
*/
public int getAge() {
return age;
}

/**
* 设置
* @param age
*/
public void setAge(int age) {
this.age = age;
}

@Override
public boolean equals(Object o) {
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return age == student.age && Objects.equals(name, student.name);
}

public String toString() {
return "Student{name = " + name + ", age = " + age + "}";
}
}

遍历

遍历方式:

  1. 迭代器
  2. 增强for(普通for:依赖于索引,只能用于List系列,Set系列没有索引,无法用)
  3. Lambda表达式

迭代器

Iterator1

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
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

public class Main {
public static void main(String[] args) {
/*
Collection系列集合三种通用的遍历方式
1.迭代器遍历
2.增强for
3.lambda

迭代器遍历相关的3个方法:
Iterator<E> iterator() 获取一个迭代器对象
boolean hasNext() 判断当前指向的位置是否有元素
E next() 获取当前指向的元素并移动指针
*/
/*
细节注意点:
1.报错NoSuchElementException
2.迭代器遍历完毕,指针不会复位
3.循环中只能用一次next方法
4.迭代器遍历时,不能用集合的方法进行增加或者删除
暂时当成一个结论记忆
如果实在要删除,可用迭代器提供的remove方法进行删除
如果要添加,暂时没有办法
*/

//1.创建集合并添加元素
Collection<String> coll = new ArrayList<>();
coll.add("aaa");
coll.add("bbb");
coll.add("ccc");
coll.add("ddd");

//2.获取迭代器对象
//迭代器好比一个箭头,默认指向集合的零索引前一个位置
Iterator<String> it = coll.iterator();
//3.利用循环不断获取集合中的每一个元素
while (it.hasNext()) {
//4.next方法:获取元素并移动指针
String str = it.next();
System.out.println(str);
}

//上面的循环结束后,迭代器的指针已经指向了最后一个元素
// System.out.println(it.next()); //NoSuchElementException

//迭代器遍历完毕,指针不会复位
System.out.println(it.hasNext());
System.out.println(it.hasNext());

//如果要继续第二次遍历,只能再次获取一个新的迭代器对象
Iterator<String> it2 = coll.iterator();
while (it2.hasNext()) {
String str = it2.next();
if ("bbb".equals(str)) {
it2.remove();
}
}
}
}

Iterator2

Iterator3

增强for

快速生成:集合名字 + for

Collection-for1

Collection-for2

lambda

Collection-lambda

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
import java.util.ArrayList;
import java.util.Collection;
import java.util.function.Consumer;

public class Main {
public static void main(String[] args) {
/*
Collection系列集合三种通用的遍历方式
1.迭代器遍历
2.增强for
3.lambda

lambda表达式遍历:
default void forEach(Consumer<? super T> action)
*/

//1.创建集合并添加元素
Collection<String> coll = new ArrayList<>();
coll.add("aaa");
coll.add("bbb");
coll.add("ccc");
coll.add("ddd");

//2.利用匿名内部类的形式
//底层原理:
//其实也会自己遍历集合,依次得到每一个元素
//把得到的每一个元素,传递给下面的accept方法
//s依次表示集合中的每一个数据
coll.forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});

//lambda表达式
coll.forEach(s -> System.out.println(s));
}
}

Collection-summary

List

List1

Vector已经被市场淘汰

方法

List2

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
import java.util.ArrayList;
import java.util.List;

public class Main {
public static void main(String[] args) {
/*
List系列集合独有的方法:
void add(int index, E element) 在此集合中的指定位置插入指定的元素
E remove(int index) 删除指定索引处的元素,返回被删除的元素
E set(int index, E element) 修改指定索引处的元素,返回被修改的元素
E get(int index) 返回指定索引处的元素
*/

//1.创建一个集合
List<String> list = new ArrayList<String>();

//2.添加元素
list.add("aaa");
list.add("bbb");
list.add("ccc");

//void add(int index, E element) 在此集合中的指定位置插入指定的元素
//细节:原来索引上的元素会依次往后移
list.add(1, "WWW");

//E remove(int index) 删除指定索引处的元素,返回被删除的元素
String remove = list.remove(2);
System.out.println(remove);

//List系列集合中的2个删除的方法
//1.直接删除元素
//2.通过索引进行删除

//1.创建集合并添加元素
List<Integer> list2 = new ArrayList<>();
list2.add(1);
list2.add(2);
list2.add(3);

//2.删除元素
//请问:此时删除的是1这个元素还是1索引的元素?
//为什么?
//因为在调用方法的时候,如果方法出现了重载现象
//优先调用,实参和形参类型一致的方法
list2.remove(1);

//手动装箱,手动把基本数据类型的1,变成Integer类型
Integer i = Integer.valueOf(1);
list.remove(i);

//E set(int index, E element) 修改指定索引处的元素,返回被修改的元素
String result = list.set(0, "QQQ");
System.out.println(result);

//E get(int index) 返回指定索引处的元素
String s = list.get(0);
System.out.println(s);

//3.打印集合
System.out.println(list);
}
}

遍历

List3

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
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;

public class Main {
public static void main(String[] args) {
/*
List系列集合的五种遍历方式:
1.迭代器
2.列表迭代器
3.增强for
4.lambda
5.普通for
*/

List<String> list = new ArrayList<String>();
list.add("aaa");
list.add("bbb");
list.add("ccc");

//1.迭代器
// Iterator<String> it = list.iterator();
// while (it.hasNext()) {
// String str = it.next();
// System.out.println(str);
// }

//2.增强for
//下面的变量s,其实就是一个第三方的变量而已
//在循环的过程中,依次表示集合中的每一个元素
for (String s : list) {
System.out.println(s);
}

//3.lambda
//forEach方法的底层其实就是一个循环遍历,依次得到集合中的每一个元素
//并把每一个元素传递给下面的accept方法
//accept方法的形参s,依次表示集合中的每一个元素
list.forEach(s -> System.out.println(s));

//4.普通for
//size方法跟get方法还有循环结合的方式,利用索引获取到集合中的每一个元素
for (int i = 0; i < list.size(); i++) {
//i:依次表示集合中的每一个索引
String s = list.get(i);
System.out.println(s);
}

//5.列表迭代器
//获取一个列表迭代器的对象,里面的指针默认也是指向第一个元素之前
//额外添加了一个方法:在遍历的过程中,可以添加元素
ListIterator<String> it = list.listIterator();
while (it.hasNext()) {
String str = it.next();
if (str.equals("aaa")) {
it.add("qqq");
}
}
}
}

List4

ArrayList

arraylist1

  • ArrayList 类:一个可调整大小的数组,在 java.util 包中

  • 数组和 ArrayList 的区别:数组大小不能修改,ArrayList可以

  • 注意:ArrayList是java已经创建好的类,在底层做了一些处理,打印对象时不是地址值,而是集合中存储的数据内容,以 [] 把所有数据进行包裹

创建

1
2
import java.util.ArrayList; 
ArrayList<String> cars = new ArrayList<>();

构造方法:

方法名 说明
public ArrayList() 创建一个空的集合对象

方法

方法名 说明
public boolean add(E e) 添加元素到末尾,返回值表示是否添加成功
public boolean remove(E e) 删除指定元素,返回值表示是否删除成功
public E remove(int index) 删除指定索引的元素,返回被删除的元素
public E set(int index,E e) 修改指定索引处的元素,返回原来的元素
public E get(int index) 获取指定索引处的元素
public int size() 获取集合中的元素的个数

删除所有元素:.clear()

遍历:

  • for

    1
    2
    3
    for (int i = 0; i < cars.size(); i++) {
    System.out.println(cars.get(i));
    }
  • for - each

    1
    2
    3
    for (String i : cars) {
    System.out.println(i);
    }

**排序: **

  • 升序:Collections.sort(...);
  • 降序:Collections.sort(..., Collections.reverseOrder());

底层原理

arraylist2

添加第一个元素:

arraylist3

一次添加多个元素:

arraylist4

LinkedList

LinkedList1

方法

LinkedList2

底层原理

LinkedList3

迭代器源码

Iterator-code

Set

特点:

  1. 无序:存取顺序不一致
  2. 不重复:可以去重复
  3. 无索引:没有带索引的方法,所以不能使用普通for循环遍历,也不能通过索引来获取元素

实现类:

  • HashSet:无序、不重复、无索引
  • LinkedHashSet:有序、不重复、无索引
  • TreeSet:可排序、不重复、无索引

Set接口中的方法上基本与Collection的API一致

方法

Collection1

遍历

  1. 迭代器
  2. 增强for
  3. lambda
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
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

public class Main {
public static void main(String[] args) {
/*
利用Set系列的集合,添加字符串,并使用多种方式遍历
1.迭代器
2.增强for
3.lambda
*/

//1.创建一个Set集合的对象
Set<String> s = new HashSet<>();

//2.添加元素
//如果当前元素是第一次添加,则添加成功,返回true
//如果当前元素是第二次添加,那么添加失败,返回false
s.add("ZhangSan");
s.add("LiSi");
s.add("WangWu");

//3.打印集合
//无序
System.out.println(s);//[WangWu, ZhangSan, LiSi]

//迭代器遍历
Iterator<String> iterator = s.iterator();
while (iterator.hasNext()) {
String str = iterator.next();
System.out.println(str);
}

//增强for
for (String str : s) {
System.out.println(str);
}

//lambda
s.forEach(str -> System.out.println(s));
}
}

Set

HashSet

底层原理:

  • HashSet集合底层采取哈希表存储数据
  • 哈希表是一种对于增删改查数据性能都较好的结构

哈希表组成:

  • JDK8之前:数组+链表
  • JDK8开始:数组+链表+红黑树

HashSet1

底层原理

哈希表:数组+链表+红黑树(JDK8)

HashSet2

HashSet3

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
86
87
88
89
90
91
92
93
94
import java.util.HashSet;
import java.util.Objects;

public class Main {
public static void main(String[] args) {
/*
创建一个存储学生对象的集合,存储多个学生对象
使用程序实现在控制台遍历该集合
要求:学生对象的成员变量相同,我们认为是同一个对象
*/

//String Integer 不需要重写

//1.创建学生对象
Student s1 = new Student("ZhangSan", 18);
Student s2 = new Student("LiSi", 18);
Student s3 = new Student("WangWu", 18);

Student s4 = new Student("ZhangSan", 18);

//2.创建集合用来添加学生
HashSet<Student> hs = new HashSet<>();

//3.添加元素,打印
System.out.println(hs.add(s1));
System.out.println(hs.add(s2));
System.out.println(hs.add(s3));
System.out.println(hs.add(s4));

System.out.println(hs);


}
}
class Student {
private String name;
private int age;

public Student() {
}

public Student(String name, int age) {
this.name = name;
this.age = age;
}

/**
* 获取
* @return name
*/
public String getName() {
return name;
}

/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}

/**
* 获取
* @return age
*/
public int getAge() {
return age;
}

/**
* 设置
* @param age
*/
public void setAge(int age) {
this.age = age;
}

@Override
public boolean equals(Object o) {
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return age == student.age && Objects.equals(name, student.name);
}

@Override
public int hashCode() {
return Objects.hash(name, age);
}

public String toString() {
return "Student{name = " + name + ", age = " + age + "}";
}
}

LinkedHashSet

LinkedHashSet1

LinkedHashSet2

TreeSet

特点:

  • 不重复、五索引、可排序
  • 可排序:按照元素的默认规则(由小到大)排序
  • TreeSet集合底层是基于红黑树的数据结构实现排序的,增删改查性能都较好
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
import java.util.Iterator;
import java.util.TreeSet;

public class Main {
public static void main(String[] args) {
/*
需求:利用TreeSet存储整数并进行排序
*/

//1.创建TreeSet集合对象
TreeSet<Integer> ts = new TreeSet<>();

//2.添加元素
ts.add(4);
ts.add(2);
ts.add(1);
ts.add(3);

//3.打印集合
System.out.println(ts);

//4.遍历
//迭代器
Iterator<Integer> it = ts.iterator();
while (it.hasNext()) {
int i = it.next();
System.out.println(i);
}

//增强for
for (Integer i : ts) {
System.out.println(i);
}

//lambda
ts.forEach(integer -> System.out.println(integer));

}
}

TreeSet集合默认规则:

  • 对于数值类型:Integer,Double,默认按照从小到大的顺序进行排序
  • 对于字符、字符串类型:按照字符在ASCII码表中的数字升序进行排序
  • 自定义类型:两种比较方式

两种比较方式

TreeSet3

方式一(默认规则):

  • Integer,Double默认升序,无法用方法一
  • 字符串默认ASCII对应数字排序,无法用方法一
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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
import java.util.TreeSet;

public class Main {
public static void main(String[] args) {
/*
需求:创建TreeSet集合,并添加3个学生对象
学生对象属性:
姓名,年龄。
要求按照学生的年龄进行排序
同年龄按照姓名字母排列(暂不考虑中文)
同行吗,同年龄认为是同一个人

方式一:
默认的排序规则/自然排序
Student实现Comparable接口,重写里面的抽象方法,再指定比较规则
*/

//1.创建3个学生对象
Student s1 = new Student("ZhangSan", 19);
Student s2 = new Student("LiSi", 18);
Student s3 = new Student("WangWu", 20);
Student s4 = new Student("ZhaoLiu", 17);

//2.创建集合对象
TreeSet<Student> ts = new TreeSet<>();

//3.添加元素
ts.add(s1);
ts.add(s2);
ts.add(s3);
ts.add(s4);

//4.打印集合
System.out.println(ts);

//hashCode和equals方法不需要重写:它们是和哈希表有关的
//TreeSet:底层是红黑树
}
}
class Student implements Comparable<Student> {
@Override
//this: 表示当前要添加的元素
//o: 表示已经在红黑树存在的元素

//返回值:
//负数:表示当前要添加的元素是小的,存左边
//正数:表示当前要添加的元素是大的,存右边
//0:表示当前要添加的元素已经存在,舍弃
public int compareTo(Student o) {
System.out.println("---------------");
System.out.println("this:" + this);
System.out.println("o:" + o);
//指定排序的规则
//只看年龄,我想要按照年龄的升序进行排列
return this.getAge() - o.getAge();
}

private String name;
private int age;

public Student() {
}

public Student(String name, int age) {
this.name = name;
this.age = age;
}

/**
* 获取
* @return name
*/
public String getName() {
return name;
}

/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}

/**
* 获取
* @return age
*/
public int getAge() {
return age;
}

/**
* 设置
* @param age
*/
public void setAge(int age) {
this.age = age;
}

public String toString() {
return "Student{name = " + name + ", age = " + age + "}";
}
}

TreeSet2

方式二

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
import java.util.Comparator;
import java.util.TreeSet;

public class Main {
public static void main(String[] args) {
/*
需求:请自行选择比较器排序和自然排序两种方式:
要求:存入四个字符串,"c", "ab", "df", "qwer"
按照长度排序,如果一样长则按照首字母排序

采取第二种排序方式:比较器排序
*/

//1.创建集合
//o1: 表示当前要添加的元素
//o2: 表示已经在红黑树存在的元素
//返回值规则跟之前是一样的
TreeSet<String> ts = new TreeSet<>(new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
//按照长度排序
int i = o1.length() - o2.length();
//如果长度一样则按照字母排序
i = i == 0 ? o1.compareTo(o2) : i;
return i;
}
});

//2.添加元素
ts.add("c");
ts.add("ab");
ts.add("df");
ts.add("qwer");

//3.打印集合
System.out.println(ts);

}
}

TreeSet4

TreeSet5

Map

方法

map2

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
import java.util.HashMap;
import java.util.Map;

public class Main {
public static void main(String[] args) {
/*
V put (K key, V value) 添加元素
V remove(Object key) 根据键删除键值对元素
void clear() 移除所有的键值对元素
boolean containsKey(Object key) 判断集合是否包含指定的键
boolean containsValue(Object value) 判断集合是否包含指定的值
boolean isEmpty() 判断集合是否为空
int size() 集合的长度,也就是集合中键值对的个数
*/

//1.创建Map集合的对象(接口多态的形式创建)
Map<String, String> m = new HashMap<>();

//2.添加元素
//put方法的细节:
//添加/覆盖
//在添加元素的时候,如果键不存在,那么直接把键值对对象添加到map集合中,方法返回null
//在添加元素的时候,如果键存在,那么会把原有的键值对对象覆盖,会把覆盖的值进行返回

m.put("A", "A");
m.put("B", "B");
m.put("C", "C");

String value1 = m.put("C", "D");
System.out.println(value1);//C

//删除
String value2 = m.remove("C");
System.out.println(value2);//D

//判断是否包含
boolean keyResult = m.containsKey("A");
System.out.println(keyResult);//true

boolean valueResult = m.containsValue("A");
System.out.println(valueResult);//true

boolean result = m.isEmpty();
System.out.println(result);//false

//清空
m.clear();

//3.打印集合
System.out.println(m);//{}
}
}

遍历

遍历方式:

  1. 键找值
  2. 键值对
  3. lambda

键找值

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
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class Main {
public static void main(String[] args) {
//Map集合的第一种遍历方式

//1.创建Map集合的对象
Map<String, String> map = new HashMap<>();

//2.添加元素
map.put("A", "A");
map.put("B", "B");
map.put("C", "C");

//3.通过键找值
//3.1获取所有的键,把这些键放到一个单列集合当中
Set<String> keys = map.keySet();
//3.2遍历单列集合,得到每一个键 (迭代器/增强for/lambda)
for (String key : keys) {
//System.out.println(key);
//3.3利用map集合的键获取对应的值 get
String value = map.get(key);
System.out.println(key + ": " + value);
}
}
}

键值对

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
public class MapDemo02 {
public static void main(String[] args) {
//Map集合的第二种遍历方式

//1.创建Map集合的对象
Map<String, String> map = new HashMap<>();

//2.添加元素
map.put("张无忌", "赵敏");
map.put("郭靖", "黄蓉");
map.put("杨过", "小龙女");

//3.Map集合的第二种遍历方式
//通过键值对对象进行遍历
//3.1通过一个方法获取所有键值对对象,返回一个Set集合
Set<Map.Entry<String, String>> entries = map.entrySet();
//3.2遍历entries集合,得到里面的每一个键值对对象
for (Map.Entry<String, String> entry : entries) {
//3.3利用entry调用get方法获取键和值
String key = entry.getKey();
String value = entry.getValue();
System.out.println(key + ":" + value);
}
}
}

lambda

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import java.util.HashMap;
import java.util.Map;

public class Main {
public static void main(String[] args) {
//Map集合的第三种遍历方式

//1.创建Map集合的对象
Map<String, String> map = new HashMap<>();

//2.添加元素
map.put("A", "A");
map.put("B", "B");
map.put("C", "C");

//3.利用lambda表达式进行遍历
//底层:
//forEach其实就是利用第二种方式进行遍历,依次得到每一个键和值
//再调用accept方法
map.forEach((key, value) -> System.out.println(key + ": " + value));
}
}

HashMap

HashMap1

HashMap2

HashMap3

HashMap4

LinkedHashMap

LinkedHashMap

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
import java.util.LinkedHashMap;

public class Main {
public static void main(String[] args) {
/*
LinkedHashMap:
由键决定:
有序、不重复、无索引
有序:
保证存储和取出的顺序一致
原理:
底层数据结构依然是哈希表,只是每个键值对元素又额外多了一个双链表的机制记录存储的顺序
*/

//1.创建集合
LinkedHashMap<String, Integer> lhm = new LinkedHashMap<>();

//2.添加元素
lhm.put("c", 789);
lhm.put("b", 456);
lhm.put("a", 123);
lhm.put("a", 111);

//3.打印集合
System.out.println(lhm);
}
}

TreeMap

TreeMap

两种比较方式

方式一(默认):无法修改Javabean源码时用方式二(Integer,Double,String等已定义好的对象)

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
86
87
88
89
90
91
92
93
94
import java.util.TreeMap;

public class Main {
public static void main(String[] args) {
/*
TreeMap集合:基本应用
需求2:
键:学生对象
值:籍贯
要求:按照学生年龄的升序排列,年龄一样按照姓名的字母排列,同姓名同年龄视为同一个人
*/

//1.创建集合对象
TreeMap<Student, String> tm = new TreeMap<>();

//2.创建3个学生对象
Student s1 = new Student("ZhangSan", 19);
Student s2 = new Student("LiSi", 18);
Student s3 = new Student("WangWu", 20);

//3.添加元素
tm.put(s1, "Beijing");
tm.put(s2, "Shanghai");
tm.put(s3, "Zhejiang");

//4.打印集合
System.out.println(tm);
}
}
class Student implements Comparable<Student> {

@Override
public int compareTo(Student o) {
//按照学生年龄的升序排列,年龄一样按照姓名的字母排列,同姓名年龄视为一个人

//this: 表示当前要添加的元素
//o: 表示已经在红黑树中存在的元素

//返回值:
//负数:表示当前要添加的元素是小的,存左边
//正数:表示当前要添加的元素是大的,存右边
//0: 表示当前要添加的元素已经存在,舍弃
int i = this.getAge() - o.getAge();
i = i == 0 ? this.getName().compareTo(o.getName()) : i;
return i;
}

public Student() {
}

public Student(String name, int age) {
this.name = name;
this.age = age;
}

private String name;
private int age;

/**
* 获取
* @return name
*/
public String getName() {
return name;
}

/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}

/**
* 获取
* @return age
*/
public int getAge() {
return age;
}

/**
* 设置
* @param age
*/
public void setAge(int age) {
this.age = age;
}

public String toString() {
return "Student{name = " + name + ", age = " + age + "}";
}
}

方式二

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
import java.util.Comparator;
import java.util.TreeMap;

public class Main {
public static void main(String[] args) {
/*
TreeMap集合:基本应用
需求1:
键:整数表示id
值:字符串表示商品名称
要求:按照id的升序排列、按照id的降序排列
*/

//1.创建集合对象
//Integer Double默认情况下都是按照升序排列的
//String 按照字母再ASCII码表对应的数字升序进行排列
//ctrl+P
TreeMap<Integer, String> tm = new TreeMap<>(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
//o1: 当前要添加的元素
//o2: 表示已经在红黑树中存在的元素
return o2 - o1;
}
});

//2.添加元素
tm.put(5, "A");
tm.put(4, "B");
tm.put(3, "C");
tm.put(2, "D");

//3.打印集合
System.out.println(tm);
}
}

TreeMap2

可变参数

args

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class Main {
public static void main(String[] args) {
//JDK5
//可变参数
//方法形参的个数是可以改变的,0,1,2,3...
//格式:属性类型...名字
//int...args
int sum = getSum(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
System.out.println(sum);
}
public static int getSum(int...args) {
System.out.println(args);//[I@4eec7777
int sum = 0;
for (int arg : args) {
sum += arg;
}
return sum;
}
}

Collections

  • java.util.Collections:是集合工具类
  • 作用:Collections不是集合,而是集合的工具类

Collections

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import java.util.ArrayList;
import java.util.Collections;

public class Main {
public static void main(String[] args) {
/*
public static <T> boolean addAll(Collection<T> c, T... element) 批量添加元素
public static void shuffle(List<?> list) 打乱List集合元素顺序
*/

//addAll 批量添加元素
//1.创建集合对象
ArrayList<String> list = new ArrayList<>();
//2.批量添加元素
Collections.addAll(list, "a", "b", "c", "d", "e", "f", "g", "h");
//3.打印集合
System.out.println(list);
//shuffle 打乱
Collections.shuffle(list);
System.out.println(list);
}
}

不可变集合

不可变集合:不可以被修改的集合

  • 长度不能修改
  • 内容不能修改

应用场景:

  • 如果某个数据不能被修改,把它防御性地拷贝到不可变集合中是个很好的实践
  • 或者当集合对象被不可信的库调用时,不可变形式是安全的

immutable-collection1

不可变的List集合

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
public class ImmutableDemo1 {
public static void main(String[] args) {
/*
创建不可变的List集合
"张三", "李四", "王五", "赵六"
*/

//一旦创建完毕之后,是无法进行修改的,在下面的代码中,只能进行查询操作
List<String> list = List.of("张三", "李四", "王五", "赵六");

System.out.println(list.get(0));
System.out.println(list.get(1));
System.out.println(list.get(2));
System.out.println(list.get(3));

System.out.println("---------------------------");

for (String s : list) {
System.out.println(s);
}

System.out.println("---------------------------");


Iterator<String> it = list.iterator();
while(it.hasNext()){
String s = it.next();
System.out.println(s);
}
System.out.println("---------------------------");

for (int i = 0; i < list.size(); i++) {
String s = list.get(i);
System.out.println(s);
}
System.out.println("---------------------------");

//报错
//list.remove("李四");
//list.add("aaa");
//list.set(0,"aaa");
}
}

不可变的Set集合

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
public class ImmutableDemo2 {
public static void main(String[] args) {
/*
创建不可变的Set集合
"张三", "李四", "王五", "赵六"


细节:
当我们要获取一个不可变的Set集合时,里面的参数一定要保证唯一性
*/

//一旦创建完毕之后,是无法进行修改的,在下面的代码中,只能进行查询操作
Set<String> set = Set.of("张三", "张三", "李四", "王五", "赵六");

for (String s : set) {
System.out.println(s);
}

System.out.println("-----------------------");

Iterator<String> it = set.iterator();
while(it.hasNext()){
String s = it.next();
System.out.println(s);
}

System.out.println("-----------------------");
//set.remove("王五");
}
}

不可变的Map集合

键值对个数小于等于10

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
public class ImmutableDemo3 {
public static void main(String[] args) {
/*
创建Map的不可变集合
细节1:
键是不能重复的
细节2:
Map里面的of方法,参数是有上限的,最多只能传递20个参数,10个键值对
细节3:
如果我们要传递多个键值对对象,数量大于10个,在Map接口中还有一个方法
*/

//一旦创建完毕之后,是无法进行修改的,在下面的代码中,只能进行查询操作
Map<String, String> map = Map.of("张三", "南京", "张三", "北京", "王五", "上海",
"赵六", "广州", "孙七", "深圳", "周八", "杭州",
"吴九", "宁波", "郑十", "苏州", "刘一", "无锡",
"陈二", "嘉兴");

Set<String> keys = map.keySet();
for (String key : keys) {
String value = map.get(key);
System.out.println(key + "=" + value);
}

System.out.println("--------------------------");

Set<Map.Entry<String, String>> entries = map.entrySet();
for (Map.Entry<String, String> entry : entries) {
String key = entry.getKey();
String value = entry.getValue();
System.out.println(key + "=" + value);
}
System.out.println("--------------------------");
}
}

键值对个数大于10

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
public class ImmutableDemo4 {
public static void main(String[] args) {

/*
创建Map的不可变集合,键值对的数量超过10个
*/

//1.创建一个普通的Map集合
HashMap<String, String> hm = new HashMap<>();
hm.put("张三", "南京");
hm.put("李四", "北京");
hm.put("王五", "上海");
hm.put("赵六", "北京");
hm.put("孙七", "深圳");
hm.put("周八", "杭州");
hm.put("吴九", "宁波");
hm.put("郑十", "苏州");
hm.put("刘一", "无锡");
hm.put("陈二", "嘉兴");
hm.put("aaa", "111");

//2.利用上面的数据来获取一个不可变的集合
/*
//获取到所有的键值对对象(Entry对象),存储在Set集合中
Set<Map.Entry<String, String>> entries = hm.entrySet();

//把Set转换为数组
Map.Entry[] arr1 = new Map.Entry[0];
Map.Entry[] arr2 = entries.toArray(arr1);
//toArray() 方法用于将 Set 集合转换为数组
//arr1 是一个长度为 0 的空数组,作为参数传递给 toArray() 方法

//toArray方法在底层会比较集合的长度跟数组的长度两者的大小
//如果集合的长度 > 数组的长度 :数据在数组中放不下,此时会根据实际数据的个数,重新创建数组
//如果集合的长度 <= 数组的长度:数据在数组中放的下,此时不会创建新的数组,而是直接用


//不可变的map集合
//Map.ofEntries() 方法将 arr2 中的所有键值对封装成一个不可变的 Map
Map map = Map.ofEntries(arr2);
map.put("bbb","222");*/


//Map<Object, Object> map = Map.ofEntries(hm.entrySet().toArray(new Map.Entry[0]));

Map<String, String> map = Map.copyOf(hm);
map.put("bbb","222");
}
}

immutable-collection2

Stream流

Stream1

使用步骤:

  1. 先得到一条Stream流(流水线),并把数据放上去
  2. 使用中间方法对流水线上的数据进行操作
  3. 使用终结方法对流水线上的数据进行操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class StreamDemo {
public static void main(String[] args) {
/*
需求:
1.创建一个集合,存储多个字符串元素
2.把集合中所有以"张"开头的元素存储到一个新的集合
3.把"张"开头的集合中的长度为3的元素存储到一个新的集合
4.遍历上一步得到的集合
*/
//集合的批量添加
ArrayList<String> list1 = new ArrayList<>(List.of("张三丰","张无忌","张翠山","王二麻子","张良","谢广坤"));

//Stream流
list1.stream().filter(name->name.startsWith("张"))
.filter(name->name.length() == 3)
.forEach(name->System.out.println(name));
}
}

获取

Stream3

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
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.stream.Stream;

public class Main {
public static void main(String[] args) {
/*
单列集合 default Stream<E> stream() Collection中的默认方法
双列集合 无 无法直接使用stream流
数组 public static <T> Stream<T> stream(T[] array) Arrays工具类中的静态方法
一堆零散数据 public static<T> Stream<T> of(T...values) Stream接口中的静态方法
*/

//1.单列集合获取Stream流
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "a", "b", "c", "d", "e", "f", "g", "h");

// //获取到一条流水线,并把集合中的数据放到流水线上
// Stream<String> stream1 = list.stream();
// //使用终结方法,打印流水线上的所有数据
// stream1.forEach(new Consumer<String>() {
// @Override
// public void accept(String s) {
// //s:依次表示流水线上的每一个数据
// System.out.println(s);
// }
// });

list.stream().forEach(s -> System.out.println(s));

//2.双列集合
HashMap<String, Integer> hm = new HashMap<>();
hm.put("a", 1);
hm.put("b", 2);
hm.put("c", 3);
hm.put("d", 4);

//第一种获取stream流
hm.keySet().stream().forEach(s -> System.out.println(s));

//第二种获取stream流=
hm.entrySet().stream().forEach(e -> System.out.println(e.getKey() + " " + e.getValue()));

//3.数组
int[] arr1 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

String[] arr2 = {"a", "b", "c", "d", "e", "f", "g", "h"};

//获取stream流
Arrays.stream(arr1).forEach(s -> System.out.println(s));

Arrays.stream(arr2).forEach(s -> System.out.println(s));

//注意:
//Stream接口中静态方法of的细节
//方法的形参是一个可变参数,可以传递一堆零散的数据,也可以传递数组
//但是数组必须是引用数据类型的,如果传递基本数据类型,是会把整个数组当作一个元素,放到Stream当中

Stream.of(arr1).forEach(s -> System.out.println(s)); //[I@b4c966a
Stream.of(arr2).forEach(s -> System.out.println(s));

//4.一堆零散数据

Stream.of(1, 2, 3, 4, 5).forEach(s -> System.out.println(s));

Stream.of("a", "b", "c", "d").forEach(s -> System.out.println(s));

Stream.of(1, 2, 3, "a", "b").forEach(s -> System.out.println(s));
}
}

中间方法

Stream2

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
import java.util.ArrayList;
import java.util.Collections;
import java.util.stream.Stream;

public class Main {
public static void main(String[] args) {
/*
filter
limit
skip
distinct
concat
map

注意1:中间方法,返回新的Stream流,原来的Stream流只能使用一次,建议使用链式编程
注意2:修改Stream流中的数据,不会影响原来集合或者数组的数据
*/

ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "张无忌", "周芷若", "赵敏", "张强", "张三丰", "张翠山", "张良", "王二麻子", "谢广坤");

//filter
// list.stream().filter(new Predicate<String>() {
// @Override
// public boolean test(String s) {
// //如果返回值为true,表示当前数据留下
// //如果返回值为false,表示当前数据舍弃不要
// return s.startsWith("张");
// }
// }).forEach(s -> System.out.println(s));

list.stream()
.filter(s -> s.startsWith("张"))
.filter(s -> s.length() == 3)
.forEach(s -> System.out.println(s));

System.out.println(list);

//limit
list.stream().limit(3).forEach(s -> System.out.println(s));
//skip
list.stream().skip(3).forEach(s -> System.out.println(s));

ArrayList<String> list2 = new ArrayList<>();
Collections.addAll(list2, "张无忌", "张无忌", "张无忌", "张强", "张三丰", "张翠山", "张良", "王二麻子", "谢广坤");

ArrayList<String> list3 = new ArrayList<>();
Collections.addAll(list3, "周芷若", "赵敏");

//distinct
list2.stream().distinct().forEach(s -> System.out.println(s));
//concat
Stream.concat(list2.stream(), list3.stream()).forEach(s -> System.out.println(s));

ArrayList<String> list4 = new ArrayList<>();
Collections.addAll(list4, "张无忌-15", "周芷若-14", "赵敏-13", "张强-20", "张三丰-100", "张翠山-40", "张良-35", "王二麻子-37", "谢广坤-38");
//需求:只获取里面的年龄进行打印
//String -> int

//第一个类型:流中原本的数据类型
//第二个类型:要转成之后的类型
// list4.stream().map(new Function<String, Integer>() {
// @Override
// public Integer apply(String s) {
// String[] arr = s.split("-");
// String ageString = arr[1];
// int age = Integer.parseInt(ageString);
// return age;
// }
// }).forEach(s -> System.out.println(s));

list4.stream()
.map(s -> Integer.parseInt(s.split("-")[1]))
.forEach(s -> System.out.println(s));
}
}

终结方法

Stream4

收集到数组:

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
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;

public class Main {
public static void main(String[] args) {
/*
void forEach(Consumer action)
long count()
toArray()
*/

ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "张无忌", "周芷若", "赵敏", "张强", "张三丰", "张翠山", "张良", "王二麻子", "谢广坤");

//forEach
//Consumer的泛型:表示流中数据的泛型
//accept方法的形参s:依次表示流里面的每一个数据
//方法体:对每一个数据的处理操作(打印)
// list.stream().forEach(new Consumer<String>() {
// @Override
// public void accept(String s) {
// System.out.println(s);
// }
// });

list.stream().forEach(s -> System.out.println(s));

//long count()
long count = list.stream().count();
System.out.println(count);

//toArray()
Object[] array = list.stream().toArray();
System.out.println(Arrays.toString(array));

//IntFunction的泛型:具体类型的数组
//apply的形参:流中数据的个数,要跟数组的长度保持一致
//apply的返回值:具体类型的数组

//toArray方法的参数的作用:负责创建一个指定类型的数组
//toArray方法的底层,会依次得到流里面的每一个数据,并把数据放到数组当中
//toArray方法的返回值:是一个装着流里面所有数据的数组
// String[] arr = list.stream().toArray(new IntFunction<String[]>() {
// @Override
// public String[] apply(int value) {
// return new String[value];
// }
// });
//
// System.out.println(Arrays.toString(arr));

String[] arr2 = list.stream().toArray(value -> new String[value]);
System.out.println(Arrays.toString(arr2));

}
}

收集到集合:

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
import java.util.*;
import java.util.stream.Collectors;

public class Main {
public static void main(String[] args) {
/*
collect(Collector collector)

注意点:如果我们要收集到Map集合当中,键不能重复,否则会报错
*/

ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "张无忌-男-15", "周芷若-女-14", "赵敏-女-13", "张强-男-20",
"张三丰-男-100", "张翠山-男-40", "张良-男-35", "王二麻子-男-37", "谢广坤-男-41");

//收集到List集合当中
//需求:
//把所有男性收集起来
List<String> newList1 = list.stream().filter(s -> "男".equals(s.split("-")[1])).collect(Collectors.toList());
System.out.println(newList1);

//收集到Set集合当中
//需求:
//把所有男性收集起来
Set<String> newList2 = list.stream().filter(s -> "男".equals(s.split("-")[1])).collect(Collectors.toSet());
System.out.println(newList2);

//收集到Map集合当中
//谁作为键,谁作为值
//把所有男性收集起来
//键:姓名 值:年龄
//张无忌-男-15
// Map<String, Integer> map = list.stream()
// .filter(s -> "男".equals(s.split("-")[1]))
// /*
// toMap: 参数一表示键的生成规则
// 参数二表示值的生成规则
// 参数一:
// Function泛型一:表示流中每一个数据类型
// 泛型二:表示Map集合中键的数据类型
//
// 方法apply形参:依次表示流里面的每一个元素
// 方法体:生成键的代码
// 返回值:已经生成的键
// 参数二:
// Function泛型一:表示流中每一个数据类型
// 泛型二:表示Map集合中值的数据类型
//
// 方法apply形参:依次表示流里面的每一个元素
// 方法体:生成值的代码
// 返回值:已经生成的值
// */
// .collect(Collectors.toMap(new Function<String, String>() {
// @Override
// public String apply(String s) {
// //张无忌-男-15
// return s.split("-")[0];
// }
// }, new Function<String, Integer>() {
// @Override
// public Integer apply(String s) {
// return Integer.parseInt(s.split("-")[2]);
// }
// }));
// System.out.println(map);

Map<String, Integer> map2 = list.stream()
.filter(s -> "男".equals(s.split("-")[1]))
.collect(Collectors.toMap(
s -> s.split("-")[0],
s -> Integer.parseInt(s.split("-")[2])
));
System.out.println(map2);
}
}

Stream5

方法引用

method-reference1

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
import java.util.Arrays;
import java.util.Comparator;

public class Main {
public static void main(String[] args) {
//需求:创建一个数组,进行倒叙排列
Integer[] arr = {3, 5, 4, 1, 6, 2};

//匿名内部类
Arrays.sort(arr, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2 - o1;
}
});

//lambda表达式
//因为第二个参数的类型Comparator是一个函数式接口
Arrays.sort(arr, (o1, o2) -> o2 - o1);

//方法引用
//1.引用处需要是函数式接口
//2.被引用的方法需要已经存在
//3.被引用方法的形参和返回值需要跟抽象方法的形参和返回值保持一致
//4.被引用方法的功能需要满足当前的需要

//表示引用Main类里面的subtraction方法
//把这个方法当作抽象方法的方法体
Arrays.sort(arr, Main::subtraction);
}

public static int subtraction(int num1, int num2) {
return num2 - num1;
}
}

method-reference2

method-reference3

引用静态方法

method-reference4

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
import java.util.ArrayList;
import java.util.Collections;
import java.util.function.Function;

public class Main {
public static void main(String[] args) {

//1.创建集合并添加元素
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "1", "2", "3", "4", "5");

//2.转换为int类型
list.stream().map(new Function<String, Integer>() {
@Override
public Integer apply(String s) {
int i = Integer.parseInt(s);
return i;
}
}).forEach(s -> System.out.println(s));

//1.方法需要已存在
//2.方法的形参和返回值需要跟抽象方法的形参和返回值保持一致
//3.方法的功能需要把形参的字符串转换成整数

list.stream().map(Integer::parseInt).forEach(s -> System.out.println(s));
}
}

引用成员方法

method-reference5

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
import java.util.ArrayList;
import java.util.Collections;
import java.util.function.Predicate;

public class Main {
public static void main(String[] args) {
/*
方法引用(引用成员方法)
格式
其他类:其他对象::方法名
本类:this::方法名
父类:super::方法名
需求:
集合中有一些名字,按照要求过滤数据
数据:”张无忌“, ”周芷若“, "赵敏", "张强", "张三丰"
要求:只要以张开头,而且名字是3个字的
*/
//1.创建集合
ArrayList<String> list = new ArrayList<>();
//2.添加数据
Collections.addAll(list, "张无忌", "周芷若", "赵敏", "张强", "张三丰");
//3.过滤数据(只要以张开头,而且名字是3个字的)
list.stream().filter(s -> s.startsWith("张")).filter(s -> s.length() == 3).forEach(s -> System.out.println(s));

//1
list.stream().filter(new Predicate<String>() {
@Override
public boolean test(String s) {
return s.startsWith("张") && s.length() == 3;
}
}).forEach(s -> System.out.println(s));

//2
StringOperation so = new StringOperation();
list.stream().filter(so::stringJudge).forEach(s -> System.out.println(s));

//3
//静态方法中是没有this的,需要new一个对象
list.stream().filter(new Main()::StringJudge).forEach(s -> System.out.println(s));
}

public boolean StringJudge(String s) {
return s.startsWith("张") && s.length() == 3;
}
}
class StringOperation {
public boolean stringJudge(String s) {
return s.startsWith("张") && s.length() == 3;
}
}

引用构造方法

method-reference6

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
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

public class Main {
public static void main(String[] args) {

//1.创建集合
ArrayList<String> list = new ArrayList<>();
//2.添加数据
Collections.addAll(list, "张无忌,15", "周芷若,14", "赵敏,13", "张强,20", "张三丰,100");
//3.封装成Student对象并收集到List集合中
//String --> Student
// List<Student> newList = list.stream().map(new Function<String, Student>() {
// @Override
// public Student apply(String s) {
// String[] split = s.split(",");
// String name = split[0];
// int age = Integer.parseInt(split[1]);
// return new Student(name, age);
// }
// }).collect(Collectors.toList());
// System.out.println(newList);

List<Student> newList2 = list.stream().map(Student::new).collect(Collectors.toList());
System.out.println(newList2);

}
}
class Student {
private String name;
private int age;

public Student() {
}

public Student(String str) {
String[] split = str.split(",");
this.name = split[0];
this.age = Integer.parseInt(split[1]);
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}

/**
* 获取
* @return name
*/
public String getName() {
return name;
}

/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}

/**
* 获取
* @return age
*/
public int getAge() {
return age;
}

/**
* 设置
* @param age
*/
public void setAge(int age) {
this.age = age;
}

public String toString() {
return "Student{name = " + name + ", age = " + age + "}";
}
}

其他调用方式

类名引用成员方法

method-reference7

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
import java.util.ArrayList;
import java.util.Collections;

public class Main {
public static void main(String[] args) {
/*
方法引用(类名引用成员方法)
格式
类名::成员方法
需求:
集合里面一些字符串,要求变成大写后进行输出

方法引用的规则:
1.需要有函数式接口
2.被引用的方法必须已经存在
3.被引用的方法的形参,需要跟抽象方法的第二个形参到最后一个形参保持一致,返回值需要保持一致
4.被引用方法的功能需要满足当前的需求

抽象方法形参的详解:
第一个参数:表示被引用方法的调用者,决定了可以引用哪些类中的方法
在Stream流当中,第一个参数一般都表示流里面的每一个数据。
假设流里面的数据是字符串,那么使用这种方式进行方法引用,只能引用String这个类中的方法

第二个参数到最后一个参数:跟被引用方法的形参保持一致,如果没有第二个参数,说明被引用的方法需要是无参的成员方法
*/

//1.创建集合
ArrayList<String> list = new ArrayList<>();
//2.添加数据
Collections.addAll(list, "aaa", "bbb", "ccc");
//3.变成大写后输出
//String --> String
// list.stream().map(new Function<String, String>() {
// @Override
// public String apply(String s) {
// return s.toUpperCase();
// }
// }).forEach(s -> System.out.println(s));

list.stream().map(String::toUpperCase).forEach(s -> System.out.println(s));

}
}

引用数组的构造方法

method-reference8

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
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;

public class Main {
public static void main(String[] args) {
/*
方法引用(数组的构造方法)
格式
数据类型[]::new
目的:
创建一个指定类型的数组
需求:
集合中存储一些整数,收集到数组当中
细节:
数组的类型,需要跟流中数据的类型保持一致
*/

//1.创建集合并添加元素
ArrayList<Integer> list = new ArrayList<>();
Collections.addAll(list, 1, 2, 3, 4, 5);

//2.收集到数组当中
// Integer[] arr = list.stream().toArray(new IntFunction<Integer[]>() {
// @Override
// public Integer[] apply(int value) {
// return new Integer[value];
// }
// });
// System.out.println(Arrays.toString(arr));

Integer[] arr2 = list.stream().toArray(Integer[]::new);
System.out.println(Arrays.toString(arr2));
}
}

method-reference9

method-reference10