Java 8 Stream 从入门到入门原创
# 我有一言 三军静听
讲在最最前面的话
Stream
这个东西吧 据说并没有什么效率的提高 之所以要用他呢 就是说某个方面让我们的💩山代码 可以不那么💩 还有吧 确实能让你装到
# 流的定义
“ A Stream is a sequence of elements from a source. 流是一个来自数据源的元素队列
简单来说,流是对数据源的包装,它允许我们对数据源进行聚合操作,并且可以方便快捷地进行批量处理
日常生活中,我们看见水流在管道中流淌 Java中的流也是可以在“管道”中传输的 并且可以在“管道”的节点进行处理,比如筛选,排序等
# 流的特征
- 流并不存储数据,所以它不是一个数据结构,它也不会修改底层的数据源,它为了函数式编程而生。
- 惰性执行的,例如filter,map等都是延迟执行的。流的中间操作总是惰性的 也就是当我们的流不存在终端操作的时候 它都懒得搭理你 都不会运行的
那么问题来了 什么是终端操作呢??
答:直接看方法的返回值,返回值为Stream的一般都是中间操作,否则是终端操作
# 流的应用
OKOK 话不多说 上点没用的小技巧
这些呢 就作为咱们一会进行测试的基础模拟数据
List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 3, 4);
List<String> stringList = Arrays.asList("a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "m", "n");
List<TestUser> userList = new ArrayList<TestUser>(){{
add(new TestUser("1", "zs", 24));
add(new TestUser("2", "ls", 35));
add(new TestUser("3", "xm", 15));
add(new TestUser("4", "xm", 12));
}};
2
3
4
5
6
7
8
9
# 🍒 filter()
接收lambda,从流中排除某些操作 就是个过滤器
List<TestUser> userList = new ArrayList<TestUser>(){{
add(new TestUser("1", "zs", 24));
add(new TestUser("2", "ls", 35));
add(new TestUser("3", "xm", 15));
add(new TestUser("4", "xm", 12));
}};
// 简单的条件
List<TestUser> collect = userList.stream().filter(p -> p.getId().equals("1"))
.collect(Collectors.toList());
System.out.println(collect); // [TestUser(id=1, name=zs, age=24)]
// 复杂点的条件
List<TestUser> collect = userList.stream().filter(p -> {
// TODO 一堆乱七八糟的逻辑处理 返回true 抽出当前数据
return true;
}).collect(Collectors.toList());
System.out.println(collect); // [TestUser(id=1, name=zs, age=24)]
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 🍒 limit()
截断流,使其元素不超过给定对象
List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 3, 4);
List<Integer> collect = integerList.stream().limit(5).collect(Collectors.toList());
System.out.println(collect); //[1, 2, 3, 4, 3]
2
3
4
# 🍒 skip(n)
跳过元素,返回一个扔掉了前n个元素的流,若流中元素不足n个,则返回一个空流 比如啊 如果咱们需要某个数据的第6到10个数据 那就可以和limit()来波小配合了
List<String> stringList = Arrays.asList("a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "m", "n");
// 首先呢 因为我们需要的是 6 - 10 先跳五个然后 截取五个 就ok了
List<String> collect = stringList.stream().skip(5).limit(5).collect(Collectors.toList());
System.out.println(collect); //[f, g, h, i, j]
2
3
4
5
# 🍒 distinct
筛选,通过流所生成元素的hashCode()和equals去除重复元素 就是去重
List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 3, 4);
List<Integer> collect = integerList.stream().distinct().collect(Collectors.toList());
System.out.println(collect); // [1, 2, 3, 4]
2
3
4
# 🍒 distinct 小进阶
去重嘛 肯定不能单纯的去重数字 字符串 来个对象搞一搞
List<TestUser> userList = new ArrayList<TestUser>(){{
add(new TestUser("1", "zs", 24));
add(new TestUser("2", "ls", 35));
add(new TestUser("3", "xm", 15));
add(new TestUser("4", "xm", 12));
}};
public static <T> Predicate<T> distinctByKey(Function<? super T, Object> keyExtractor) {
Map<Object, Boolean> seen = new ConcurrentHashMap<>();
return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
}
// 如果需要多个字段 可以拼一块 感觉太难看的话 那就再跟一个filter也可以
List<TestUser> collect = userList.stream()
.filter(distinctByKey((p) -> (p.getName()))).collect(Collectors.toList());
System.out.println(collect); // [TestUser(id=1, name=zs, age=24), TestUser(id=2, name=ls, age=35), TestUser(id=3, name=xm, age=15)]
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 🍒 map 及扩展
接受Lambda,将元素转换成其他形式或提取信息。接受一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素
List<TestUser> userList = new ArrayList<TestUser>(){{
add(new TestUser("1", "zs", 24));
add(new TestUser("2", "ls", 35));
add(new TestUser("3", "xm", 15));
add(new TestUser("4", "xm", 12));
}};
List<String> collect = userList.stream().map(TestUser::getName).collect(Collectors.toList());
System.out.println(collect); // [zs, ls, xm, xm]
int sum = userList.stream().mapToInt(TestUser::getAge).sum();
System.out.println(sum); // 86
2
3
4
5
6
7
8
9
10
11
12
# 🍒 sorted()
自然排序(Comparable)
List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 3, 4);
List<Integer> collect = integerList.stream().sorted().collect(Collectors.toList());
System.out.println(collect); // [1, 2, 3, 3, 4, 4]
2
3
4
# 🍒 sorted(Comparatorcom)
相比上一种呢 我们可以自定义排序 不光如此 其他的用法也一并整到这里面了 多不代表全
List<TestUser> userList = new ArrayList<TestUser>(){{
add(new TestUser("1", "zs", 24));
add(new TestUser("2", "ls", 35));
add(new TestUser("3", "xm", 15));
add(new TestUser("4", "xm", 12));
}};
List<TestUser> collect = userList.stream()
.sorted(Comparator.comparing(TestUser::getAge)).collect(Collectors.toList());
System.out.println(collect);
/** [TestUser(id=4, name=xm, age=12),
TestUser(id=3, name=xm, age=15),
TestUser(id=1, name=zs, age=24),
TestUser(id=2, name=ls, age=35)] **/
// 默认都是升序 但是我们可以强制修改为倒序
List<TestUser> collect = userList.stream()
.sorted(Comparator.comparing(TestUser::getAge).reversed())
.collect(Collectors.toList());
System.out.println(collect);
/** [TestUser(id=2, name=ls, age=35),
* TestUser(id=1, name=zs, age=24),
* TestUser(id=3, name=xm, age=15),
* TestUser(id=4, name=xm, age=12)] **/
// 剩下的呢 就不打印结果了 只是看下写法
// 根据AGE进行降序 然后根据AGE进行升序
List<TestUser> collect = userList.stream()
.sorted(Comparator.comparing(TestUser::getAge)
.reversed()
.thenComparing(TestUser::getAge))
.collect(Collectors.toList());
// 都是降序
List<TestUser> collect = userList.stream()
.sorted(Comparator.comparing(TestUser::getAge)
.thenComparing(TestUser::getId)
.reversed())
.collect(Collectors.toList());
// 都是升序
List<TestUser> collect = userList.stream()
.sorted(Comparator.comparing(TestUser::getAge)
.thenComparing(TestUser::getId))
.collect(Collectors.toList());
// 先正序 后倒序 这个之所以第一个变成正序 是因为刚开始倒序 后来走到第二步 倒倒就正了
List<TestUser> collect = userList.stream()
.sorted(Comparator.comparing(TestUser::getAge)
.reversed()
.thenComparing(TestUser::getId)
.reversed())
.collect(Collectors.toList());
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
# 🍒 allMatch anyMatch noneMatch
以上三个 其实意思都大差不差 放一起了
- allMatch 检查是否匹配所有元素
- anyMatch 检查是否至少匹配一个元素
- noneMatch 检查是否没有匹配所有元素
List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 3, 4);
// 全部不等于零
boolean b = integerList.stream().allMatch(p -> p != 0);
System.out.println(b); // true
// 存在一个等于三
boolean b1 = integerList.stream().anyMatch(p -> p == 3);
System.out.println(b1); // true
// 没有一个不等于零的
boolean b2 = integerList.stream().noneMatch(p -> p != 0);
System.out.println(b2); // false
// 没有一个等于零的
boolean b3 = integerList.stream().noneMatch(p -> p == 0);
System.out.println(b3); // true
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 🍒 findFirst
返回第一个元素
List<TestUser> userList = new ArrayList<TestUser>(){{
add(new TestUser("1", "zs", 24));
add(new TestUser("2", "ls", 35));
add(new TestUser("3", "xm", 15));
add(new TestUser("4", "xm", 12));
}};
TestUser testUser = userList.stream().findFirst().get();
System.out.println(testUser); // TestUser(id=1, name=zs, age=24)
2
3
4
5
6
7
8
9
# 🍒 findAny
返回当前流中的任意元素 随机的意思 正常情况下一般会取第一个元素,在并行流的情况下会随机取一个元素
List<TestUser> userList = new ArrayList<TestUser>(){{
add(new TestUser("1", "zs", 24));
add(new TestUser("2", "ls", 35));
add(new TestUser("3", "xm", 15));
add(new TestUser("4", "xm", 12));
}};
TestUser testUser = userList.stream().findAny().get();
System.out.println(testUser); // TestUser(id=1, name=zs, age=24)
2
3
4
5
6
7
8
9
# 🍒 count
返回流中元素的总个数
List<String> stringList = Arrays.asList("a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "m", "n");
long count = stringList.stream().count();
System.out.println(count);// 13
2
3
# 🍒 max
- max 返回流中最大值
- min 返回流中最小值
List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 3, 4);
// 参数无非就是比较器
Integer max = integerList.stream().max(Integer::compareTo).get();
Integer min = integerList.stream().min(Integer::compareTo).get();
System.out.println(max); // 4
System.out.println(min); // 1
2
3
4
5
6
7
# 🍒 reduce
归约操作可以将流中元素反复结合起来,得到一个值
List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 3, 4);
// 来个四以内的加减吧
Integer reduce = integerList.stream().reduce(0, Integer::sum);
System.out.println(reduce); // 17
List<String> stringList = Arrays.asList("a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "m", "n");
String s = stringList.stream().reduce((acc, item) -> {
acc += "-" + item;
return acc;
}).get();
System.out.println(s); // a-b-c-d-e-f-g-h-i-j-k-m-n
2
3
4
5
6
7
8
9
10
11
12
# 🍒 collect
将流转换为其他形式,接收一个Collector接口实现,用于给Stream中汇总的方法 上面基本上每个实例中都能见到 就不举例了 往上瞅
# 总结
当你看的这里的时候 大致也就是结束了 还是那句话 咱就是个编撰 别硬刚 目前就这些东西 或许还添 也可能吃灰 谁知道呢 下班 回家干饭