Java Stream流

  • 创建不可变集合
  • Stream流
  • 方法引用

创建不可变集合

所谓的不可变集合是指不可以被修改的集合,即长度不可修改、内容也不可修改

不可变集合应用场景:

不想让别人修改集合里的内容

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

    比如:

  • 扑克牌集合,一共4*13=52张牌,不允许添加新的牌

  • 出牌游戏规则
  • 电脑里的硬件信息,这些信息电脑开机获取,开机之后不允许其他程序修改

如何创建不可变的集合:

List、Set、Map 接口中,都存在静态的of方法,可以获取一个不可变的集合,这个集合不能添加,不能删除,也不能修改

注意:of方法在JDK9里面才有

image-20240629092648239

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.example;

import java.util.List;

public class UnMutableDemo {
public static void main(String[] args) {
List<String> stringList = List.of("张三", "李四", "王五", "赵六");
for (String s : stringList) {
System.out.println(s);
}
//Exception in thread "main" java.lang.UnsupportedOperationException
//stringList.remove(0);
//Exception in thread "main" java.lang.UnsupportedOperationException
stringList.add("12");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
public class UnMutableDemo {
public static void main(String[] args) {
List<String> lists = new ArrayList<>();
lists.add("12");
lists.add("32");
lists.add("56");
lists.remove(1);
//原始集合拷贝为不可变集合
List<String> unMutateList = List.copyOf(lists);
System.out.println(unMutateList);
}
}

Stream流

背景

image-20240629100818381

如果用常规for循环遍历的话,代码会非常繁琐,但是用stream流会非常简洁

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class StreamDemo {
public static void main(String[] args) {
List<String> nameList = new ArrayList<>();
nameList.add("张无忌");
nameList.add("周芷若");
nameList.add("赵敏");
nameList.add("张强");
nameList.add("张三丰");
//for循环做法
List<String> newNameList1 = new ArrayList<>();
for (String s : nameList) {
if(s.startsWith("张") && s.length()==3){
newNameList1.add(s);
}
}
System.out.println(newNameList1);
//stream流
List<String> newNameList2 = nameList.stream().filter(name -> name.startsWith("张")).filter(name -> name.length() == 3).collect(Collectors.toList());
System.out.println(newNameList2);
}
}

Stream流使用

stream流使用步骤

image-20240629102310459

image-20240629102549826

获取stream流

image-20240629102618143

对于双列集合(map)需要先调用keySet或者entrySet转换成单列集合,再调用Stream方法获取流水线

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
public class StreamDemo {
public static void main(String[] args) {
//1.单列集合获取流水线
List<String> list = new ArrayList<>();
Collections.addAll(list,"张三","李四","王五","赵六");
//获取流水线,并调用终结方法打印元素
list.stream().forEach(item-> System.out.println(item));

//2.双列集合获取流水线
Map<String,Integer> map = new HashMap<>();
map.put("张三",100);
map.put("李四",200);
map.put("王五",300);
map.put("赵六",400);
//方法一:通过keySet()获取流水线
map.keySet().stream().forEach(s-> System.out.println(s+"="+map.get(s)));
//方法二:通过entrySet()获取流水线
map.entrySet().stream().forEach(s-> System.out.println(s));

//3.数组获取流水线 Arrays.stream()
String[] hobbys = {"篮球","足球","乒乓球","橄榄球"};
Arrays.stream(hobbys).forEach(s-> System.out.println(s));

//4.零散数据获取数据流,Stream.of(),但是要保证这些零散数据是同一数据类型
Stream.of("小学","初中","高中","大学").forEach(s-> System.out.println(s));
}
}

Stream流中间方法

image-20240629105106596

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
public class example {
List<String> nameList=null;
@Before
public void init(){
nameList = new ArrayList<>();
Collections.addAll(nameList,"曹操","司马懿","赵云","关云长","写宅院");

}
@Test
public void testFilter(){
//filter过滤,过滤掉不满足条件的元素
//打印长度大于等于3的人名
nameList.stream().filter(name->name.length()>=3).forEach(name-> System.out.println(name));
}

@Test
public void TestLimit(){
//limit,取流中的求几个元素
nameList.stream().limit(3).forEach(name-> System.out.println(name));
/*
曹操
司马懿
赵云
*/
}

@Test
public void TestSkip(){
//skip,跳过流中的求几个元素
nameList.stream().skip(3).forEach(name-> System.out.println(name));
/*
关云长
写宅院
*/
}

@Test
public void TestDistict(){
//distinct流中元素去重
//里面本质是借助于HashSet进行去重,所以非基础类型数据时,要关注重写hashCode和equals方法
List<Integer> list = new ArrayList<>();
Collections.addAll(list,21,23,22,9,80,22,9);
list.stream().distinct().forEach(s-> System.out.print(s+" "));
//21 23 22 9 80
}

@Test
public void TestConcat(){
//concat合并两个流,这两个流里面元素的数据类型最好要一致
List<String> list1 = new ArrayList<>();
Collections.addAll(list1,"中国","日本","韩国","朝鲜");
List<String> list2 = new ArrayList<>();
Collections.addAll(list2,"英国","法国","德国");
Stream.concat(list1.stream(),list2.stream()).forEach(s-> System.out.print(s+" "));
//中国 日本 韩国 朝鲜 英国 法国 德国
}

@Test
public void TestMap(){
//map可以对流中元素进行操作,以及数据类型转换
List<Integer> list = new ArrayList<>();
Collections.addAll(list,3,5,7,1,9);
//比如对流中所有元素进行如下运算,将结果打印: i*i+10
list.stream().map(i->i*i+10).forEach(s-> System.out.print(s+" "));
//19 35 59 11 91
}
}

Stream流中间方法

image-20240629112458751

1
2
3
4
5
6
7
8
9
10
@Test
public void TestCount(){
//终结方法 count,统计流中元素个数
//map可以对流中元素进行操作,以及数据类型转换
List<Integer> list = new ArrayList<>();
Collections.addAll(list,3,5,7,1,9);
long count = list.stream().count();
System.out.println(count);

}
1
2
3
4
5
6
7
8
9
@Test
public void TestToArray(){
//toArray将流中的结果放入数组
List<String> list = new ArrayList<>();
Collections.addAll(list,"中国","日本","韩国","朝鲜");
//value为流中元素个数
String[] array = list.stream().toArray(value -> new String[value]);
System.out.println(Arrays.toString(array));
}
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
@Test
public void TestToList(){
//流转换为list
List<String> list = new ArrayList<>();
Collections.addAll(list,"关羽-男-32","刘备-男-38","张飞-男-23","貂蝉-女-12","孙尚香-女-31");
//将list中所有男性成员姓名组装成一个list
List<String> nameList = list.stream()
.filter(s -> "男".equals(s.split("-")[1]))
.map(s -> s.split("-")[0])
.collect(Collectors.toList());
System.out.println(nameList);
//[关羽, 刘备, 张飞]
}
@Test
public void TestToSet(){
//流转换为lset
List<String> list = new ArrayList<>();
Collections.addAll(list,"关羽-男-32","刘备-男-38","张飞-男-23","貂蝉-女-12","孙尚香-女-31");
//将list中所有男性成员姓名组装成一个list
Set<String> nameSet = list.stream()
.filter(s -> "男".equals(s.split("-")[1]))
.map(s -> s.split("-")[0])
.collect(Collectors.toSet());
System.out.println(nameSet);
//[关羽, 刘备, 张飞]
}

@Test
public void TestToMap(){
//转换为map
//组成:key为姓名,value为年龄
List<String> list = new ArrayList<>();
Collections.addAll(list,"关羽-男-32","刘备-男-38","张飞-男-23","貂蝉-女-12","孙尚香-女-31");
/**
* Collectors.toMap(参数1,参数2):
* 参数1为map key的生成规则
* 参数2为map value的生成规则
*/
Map<String, Integer> map = list.stream().collect(Collectors.toMap(
s -> s.split("-")[0], s -> Integer.parseInt(s.split("-")[2])
));
System.out.println(map);
//{关羽=32, 张飞=23, 刘备=38, 貂蝉=12, 孙尚香=31}
}