Stream流 && 方法引用
:star: Stream流
将数据变成流水线可以进行中间方法和最终方法
1. 初识Stream
1 | public class StreamDemo { |
2. Stream流在各个数据类型中的应用
2.1数组
-
Arrays. stream
1
2
3
4
5int[] array01 = {1,2,3,4,5,6,7,8,9};
String[] array02 = {"1", "2", "3", "4", "5"};
Arrays.stream(array01).forEach(System.out::println);
Arrays.stream(array02).forEach(System.out::println); -
Stream. of
需要注意
Stram
中的静态方法of只能传递引用数据类型of中的形参数据类型需要一样
1
2
3
4
5int[] array01 = {1,2,3,4,5,6,7,8,9};
String[] array02 = {"1", "2", "3", "4", "5"};
Stream.of(array01).forEach(System.out::println); //[I@404b9385
Stream.of(array02).forEach(System.out::println);
2.2集合
-
单列集合
1
2list.stream()
set.stream() -
双列集合
1
2hm.keySet().stream()
hm.entrySet().stream()
3. Stream流中间方法
- 中间方法,返回新的Stream流,原来的Stream流只能使用一次,建议使用链式编程
- 修改Stream流中的数据,不会影响原来集合或者数组中的数据
3.1 常见方法
方法名 | 说明 |
---|---|
Stream |
用于对流中的数据进行过滤 |
Stream |
返回此流中的元素组成的流,截取前指定参数个数的数据 |
Stream |
跳过指定参数个数的数据,返回由该流的剩余元素组成的流 |
static |
合并a和b两个流为一个流 |
Stream |
返回由该流的不同元素(根据Object.equals(Object) )组成的流 |
3.2 代码演示
-
filter代码演示
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
41public class MyStream3 {
public static void main(String[] args) {
// Stream<T> filter(Predicate predicate):过滤
// Predicate接口中的方法 boolean test(T t):对给定的参数进行判断,返回一个布尔值
ArrayList<String> list = new ArrayList<>();
list.add("张三丰");
list.add("张无忌");
list.add("张翠山");
list.add("王二麻子");
list.add("张良");
list.add("谢广坤");
//filter方法获取流中的 每一个数据.
//而test方法中的s,就依次表示流中的每一个数据.
//我们只要在test方法中对s进行判断就可以了.
//如果判断的结果为true,则当前的数据留下
//如果判断的结果为false,则当前数据就不要.
// list.stream().filter(
// new Predicate<String>() {
// @Override
// public boolean test(String s) {
// boolean result = s.startsWith("张");
// return result;
// }
// }
// ).forEach(s-> System.out.println(s));
//因为Predicate接口中只有一个抽象方法test
//所以我们可以使用lambda表达式来简化
// list.stream().filter(
// (String s)->{
// boolean result = s.startsWith("张");
// return result;
// }
// ).forEach(s-> System.out.println(s));
list.stream().filter(s ->s.startsWith("张")).forEach(s-> System.out.println(s));
}
} -
limit&skip代码演示
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24public class StreamDemo02 {
public static void main(String[] args) {
//创建一个集合,存储多个字符串元素
ArrayList<String> list = new ArrayList<String>();
list.add("林青霞");
list.add("张曼玉");
list.add("王祖贤");
list.add("柳岩");
list.add("张敏");
list.add("张无忌");
//需求1:取前3个数据在控制台输出
list.stream().limit(3).forEach(s-> System.out.println(s));
System.out.println("--------");
//需求2:跳过3个元素,把剩下的元素在控制台输出
list.stream().skip(3).forEach(s-> System.out.println(s));
System.out.println("--------");
//需求3:跳过2个元素,把剩下的元素中前2个在控制台输出
list.stream().skip(2).limit(2).forEach(s-> System.out.println(s));
}
} -
concat&distinct代码演示
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25public class StreamDemo03 {
public static void main(String[] args) {
//创建一个集合,存储多个字符串元素
ArrayList<String> list = new ArrayList<String>();
list.add("林青霞");
list.add("张曼玉");
list.add("王祖贤");
list.add("柳岩");
list.add("张敏");
list.add("张无忌");
//需求1:取前4个数据组成一个流
Stream<String> s1 = list.stream().limit(4);
//需求2:跳过2个数据组成一个流
Stream<String> s2 = list.stream().skip(2);
//需求3:合并需求1和需求2得到的流,并把结果在控制台输出
// Stream.concat(s1,s2).forEach(s-> System.out.println(s));
//需求4:合并需求1和需求2得到的流,并把结果在控制台输出,要求字符串元素不能重复
Stream.concat(s1,s2).distinct().forEach(s-> System.out.println(s));
}
}
4. Stream流终结方法
终结操作的意思是,执行完此方法之后,Stream流将不能再执行其他操作
4.1 常见方法
方法名 | 说明 |
---|---|
void forEach(Consumer action) | 对此流的每个元素执行操作 |
long count() | 返回此流中的元素数 |
toArray(有参/空参) | 创建一个数组,并且将流中的数据放入到数组中 |
collect | 收集方法,将数据变成集合 |
4.2 代码演示
-
forEach
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// void forEach(Consumer action):对此流的每个元素执行操作
// Consumer接口中的方法void accept(T t):对给定的参数执行此操作
//在forEach方法的底层,会循环获取到流中的每一个数据.
//并循环调用accept方法,并把每一个数据传递给accept方法
//s就依次表示了流中的每一个数据.
//所以,我们只要在accept方法中,写上处理的业务逻辑就可以了.
list.stream().forEach(
new Consumer<String>() {
public void accept(String s) {
System.out.println(s);
}
}
);
System.out.println("====================");
//lambda表达式的简化格式
//是因为Consumer接口中,只有一个accept方法
list.stream().forEach(
(String s)->{
System.out.println(s);
}
);
System.out.println("====================");
//lambda表达式还是可以进一步简化的.
list.stream().forEach(s->System.out.println(s)); -
count
1
Long l = list.stream().count()
-
toArray()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22ArrayList<String> list = new ArrayList<>();
list.add("张三丰");
list.add("张无忌");
list.add("张翠山");
list.add("王二麻子");
list.add("张良");
list.add("谢广坤");
String[] arr = list.stream().toArray(new IntFunction<String[]>() {
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)); -
collect
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
92package com.itheima.a01mystream;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
public class StreamDemo10 {
public static void main(String[] args) {
/*
collect(Collector collector) 收集流中的数据,放到集合中 (List Set Map)
注意点:
如果我们要收集到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集合当中
//谁作为键,谁作为值.
//我要把所有的男性收集起来
//键:姓名。 值:年龄
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>() {
public String apply(String s) {
//张无忌-男-15
return s.split("-")[0];
}
},
new Function<String, Integer>() {
public Integer apply(String s) {
return Integer.parseInt(s.split("-")[2]);
}
}));
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);
}
}
5.Stream流综合训练
-
案例需求
现在有两个ArrayList集合,分别存储6名男演员名称和6名女演员名称,要求完成如下的操作
- 男演员只要名字为3个字的前三人
- 女演员只要姓林的,并且不要第一个
- 把过滤后的男演员姓名和女演员姓名合并到一起
- 把上一步操作后的元素作为构造方法的参数创建演员对象,遍历数据
演员类Actor已经提供,里面有一个成员变量,一个带参构造方法,以及成员变量对应的get/set方法
-
代码实现
演员类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15public class Actor {
private String name;
public Actor(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}测试类
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
35public class StreamTest {
public static void main(String[] args) {
//创建集合
ArrayList<String> manList = new ArrayList<String>();
manList.add("周润发");
manList.add("成龙");
manList.add("刘德华");
manList.add("吴京");
manList.add("周星驰");
manList.add("李连杰");
ArrayList<String> womanList = new ArrayList<String>();
womanList.add("林心如");
womanList.add("张曼玉");
womanList.add("林青霞");
womanList.add("柳岩");
womanList.add("林志玲");
womanList.add("王祖贤");
//男演员只要名字为3个字的前三人
Stream<String> manStream = manList.stream().filter(s -> s.length() == 3).limit(3);
//女演员只要姓林的,并且不要第一个
Stream<String> womanStream = womanList.stream().filter(s -> s.startsWith("林")).skip(1);
//把过滤后的男演员姓名和女演员姓名合并到一起
Stream<String> stream = Stream.concat(manStream, womanStream);
// 将流中的数据封装成Actor对象之后打印
stream.forEach(name -> {
Actor actor = new Actor(name);
System.out.println(actor);
});
}
}
:star: 方法引用
把已经有的方法拿过来用,当作函数式接口中抽象方法的方法体
1. 样例
1 | package com.itheima.a01myfunction; |
2. 方法引用的分类
2.1 引用静态方法
- 格式:类名
::
静态方法 - 范例:
Integet::parseInt
1 | package com.yyh.funcationdemo; |
2.2 引用成员方法
- 格式:对象
::
成员方法 - 其他类:其他类对象
::
方法名 - 本类:this
::
方法名 - 父类:super
::
方法名
2.2.1 引用其他类对象
其他类对象::
方法名
1 | package com.yyh.funcationdemo; |
2.2.2 引用本类对象
注意静态中是没有this关键字的
1 | package com.yyh.funcationdemo; |
2.3 引用构造方法
- 格式:类名
::
new - 范例:Student
::
new
实现类
1 | package com.itheima.a01myfunction; |
Student类:
1 | package com.itheima.a01myfunction; |
2.4 其他调用方式
2.4.1 使用类名引用成员方法
- 格式:类名
::
成员方法 - 范例:
String::substring
1 | package com.itheima.a01myfunction; |
2.4.1引用数组的构造方法
- 格式:数据类型[]
::
new - 范例:
int[]::new
1 | package com.itheima.a01myfunction; |
1 | package com.itheima.a01myfunction; |
评论