Stream
介绍
java8 添加了一个抽象流 Stream, 可以让我们像写 sql 一样操作集合元素. Stream 将要处理的元素看做是一种流, 在管道中传输, 并进行处理, 最后由终止操作得到处理的结果.
什么是 Stream?
Stream 是一个来自特定元素队列并支持聚合操作
元素是具体类型的对象, 形成一个队列.
数据源是流的来源.
聚合操作是类似 sql 一样的操作, 比如 filter, map, reduce, find, match, sorted 等.
Stream 自己不会存储元素.
Stream 不会改变源对象.
Stream 操作是延迟执行的.
创建流
串行流
stream(): 即单线程的方式去操作流
并行流
parallelStream(): 即多线程方式去操作流
- @Test
- public void test() {
- //1 通过 Collection 提供的 stream()和 parallelStream()方法
- List<String> list = Arrays.asList("a","b","c");
- Stream<String> stream1 = list.stream();
- Stream<String> stream2 = list.parallelStream();
- //2 通过 Arrays 的静态方法 stream()
- String[] strs= {"a","b","c"};
- Stream<String> stream3 = Arrays.stream(strs);
- //3 通过 Stream 类中的静态方法 of()
- Stream<String> stream4 = Stream.of("a","b","c");
- //4 通过 Stream 类的 iterate 方法生成无限流
- Stream<Integer> stream5 = Stream.iterate(0, (x)->x+1);
- //5 通过 Stream 的 generate 方法生成无限流
- Stream.generate(()->Math.random());
- }
中间操作
过滤
使用 filter(Predicate<? super T> predicate)来按照一定规则对流中元素进行过滤
- @Test
- public void test() {
- List<Integer> list = Arrays.asList(1,2,3,4,5);
- Stream<Integer> stream = list.stream();
- stream = stream.filter((x)->x.compareTo(2)>0);
- stream.forEach(System.out::println);
- }
输出:
- 3
- 4
- 5
- @Test
- public void test2() {
- List<Integer> list = Arrays.asList(1,2,3,4,5);
- Stream<Integer> stream = list.stream();
- stream = stream.filter(
- (x)->{
- System.out.println(x);
- return x.compareTo(2)>0;}
- );
- }
结果: 没有任何输出, 这也就是前面说的 Stream 操作是延迟执行的, 只有当终止操作这些中间操作才会依次执行
截断
使元素的个数不超过指定的数目
- @Test
- public void test() {
- List<Integer> list = Arrays.asList(1,2,3,4,5);
- Stream<Integer> stream = list.stream();
- stream=stream.limit(3);
- stream.forEach(System.out::println);
- }
输出:
1
2
3
可以看到只输出了给定个元素
跳过元素
跳过流中前几个元素
- @Test
- public void test4() {
- List<Integer> list = Arrays.asList(1,2,3,4,5);
- Stream<Integer> stream = list.stream();
- stream=stream.skip(2);
- stream.forEach(System.out::println);
- }
输出:
3
4
5
跳过了前两个元素
唯一筛选
两个元素通过 hashCode()判断两个元素是否相同
- @Test
- public void test5() {
- List<Integer> list = Arrays.asList(1,2,3,4,5,5);
- Stream<Integer> stream = list.stream();
- stream.distinct().forEach(System.out::println);
- }
输出:
1
2
3
4
5
映射
map(method)接受一个方法, 把流中的元素按照方法进行转换
- @Test
- public void test() {
- List<String> list = Arrays.asList("a","b","c");
- Stream<String> stream = list.stream();
- stream=stream.map((x)->x.toUpperCase());
- stream.forEach(System.out::println);
- }
输出:
A
B
C
flatMap(method)也是接受一个函数作为参数, 但是与 map, 不同的是如果这个函数生成的本来就是流, 它会把函数生成流中的元素加到流中
- // 这个函数本身就生成流
- public static Stream<Character> toStream(String s){
- List<Character> list=new ArrayList<Character>();
- char[] chs = s.toCharArray();
- for (char c : chs) {
- list.add(c);
- }
- Stream<Character> stream = list.stream();
- return stream;
- }
- @Test
- public void test() {
- List<String> list = Arrays.asList("aaa","bbb","ccc");
- Stream<Stream<Character>> stream =
- // 由于函数本身就生成流, 所以流中加入的还是流
- list.stream().map(StreamTest::toStream);
- // 遍历的时候需要先从流中取出流, 在遍历
- stream.forEach((s)->s.forEach(System.out::println));
- }
- // 然而我们可以使用 flatMap 进行改进
- @Test
- public void test() {
- List<String> list = Arrays.asList("aaa","bbb","ccc");
- list.stream().flatMap(StreamTest::toStream).forEach(System.out::println);
- }
输出:
- a
- a
- a
- b
- b
- b
- c
- c
- c
终止操作
所有匹配
当所有元素都匹配时, allMatch(Predicate<? super T> predicate)才会返回 true
- @Test
- public void test() {
- List<String> list = Arrays.asList("aaa","bbb","ccc");
- boolean allMatch = list.stream().allMatch((s)->s.length()>2);
- System.out.println(allMatch);
- }
输出:
true
任一匹配
当 Stream 中任一一个元素匹配时, anyMatch(Predicate<? super T> predicate)返回 true
- @Test
- public void test() {
- List<String> list = Arrays.asList("aaa","bbb","ccc");
- boolean anyMatch = list.stream().anyMatch((s)->s.equals("bbb"));
- System.out.println(anyMatch);
- }
输出:
true
所有不匹配
当 Stream 中所有的元素都不匹配时, noneMatch(Predicate<? super T> predicate)返回 true
- @Test
- public void test() {
- List<String> list = Arrays.asList("aaa","bbb","ccc");
- boolean noneMatch = list.stream().noneMatch((s)->s.equals("ddd"));
- System.out.println(noneMatch);
- }
输出:
true
第一个元素
返回当前流中的第一个元素
- @Test
- public void test() {
- List<Integer> list = Arrays.asList(1,2,3,4,5);
- Optional<Integer> findFirst = list.stream().findFirst();
- System.out.println(findFirst.get());
- }
输出:
1
任一一个元素
返回当前流中的任一一个元素
- @Test
- public void test() {
- List<Integer> list = Arrays.asList(1,2,3,4,5);
- Optional<Integer> findAny = list.stream().findAny();
- System.out.println(findAny.get());
- }
输出:
- 1
- // 使用并行流试试
- @Test
- public void test13() {
- List<Integer> list = Arrays.asList(1,2,3,4,5);
- Optional<Integer> findAny = list.parallelStream().findAny();
- System.out.println(findAny.get());
- }
输出:
3
流中元素个数
返回流中的元素个数
- @Test
- public void test14() {
- List<Integer> list = Arrays.asList(1,2,3,4,5);
- long count = list.stream().count();
- System.out.println(count);
- }
输出:
5
流中的最大值
返回流中元素的最大值
- @Test
- public void test15() {
- List<Integer> list = Arrays.asList(1,2,3,4,5);
- Optional<Integer> max = list.stream().max(Integer::compare);
- System.out.println(max.get());
- }
输出:
5
流中的最小值
返回流中的最小值
- @Test
- public void test16() {
- List<Integer> list = Arrays.asList(1,2,3,4,5);
- Optional<Integer> min = list.stream().min(Integer::compare);
- System.out.println(min.get());
- }
输出:
1
规约
将流中的元素反复结合得到一个最终值
- @Test
- public void test() {
- List<Integer> list = Arrays.asList(1,2,3,4,5);
- Optional<Integer> reduce = list.stream().reduce(Integer::sum);
- System.out.println(reduce.get());
- Integer reduce2 = list.stream().reduce(0, (x,y)->{
- System.out.println(x+"->"+y);
- return x+y;
- });
- System.out.println(reduce2);
- }
输出:
- 15
- 0->1
- 1->2
- 3->3
- 6->4
- 10->5
- 15
可以看到当使用 (T identity, BinaryOperatoraccumulator) 时, identity 即为最初和流中元素进行运算的, 所以值不能为空, 所以返回的不是 Optional
收集
将流转换成其他形式
- @Test
- public void test() {
- List<Integer> list = Arrays.asList(1,2,3,4,5,5);
- Set<Integer> collect = list.stream().collect(Collectors.toSet());
- System.out.println(collect);
- }
输出:
- [1, 2, 3, 4, 5]
- @Test
- public void test() {
- List<Integer> list = Arrays.asList(1,2,3,4,5,5);
- Optional<Integer> collect = list.stream().collect(Collectors.maxBy(Integer::compareTo));
- System.out.println(collect.get());
- }
输出:
- 5
- class Stu{
- String name;
- Integer age;
- String gender;
- public Stu(String name, Integer age, String gender) {
- super();
- this.name = name;
- this.age = age;
- this.gender = gender;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public Integer getAge() {
- return age;
- }
- public void setAge(Integer age) {
- this.age = age;
- }
- public String getGender() {
- return gender;
- }
- public void setGender(String gender) {
- this.gender = gender;
- }
- @Override
- public String toString() {
- return "Stu [name=" + name + ", age=" + age + ", gender=" + gender + "]";
- }
- }
- // 一级分组
- @Test
- public void test() {
- List<Stu> list = Arrays.asList(
- new Stu("张三",20,"男"),
- new Stu("李四",22,"女"),
- new Stu("王五",18,"男"),
- new Stu("赵六",20,"女"),
- new Stu("田七",22,"女")
- );
- Map<String, List<Stu>> collect = list.stream().collect(Collectors.groupingBy(Stu::getGender));
- System.out.println(collect);
- }
输出:
{女 =[Stu [name = 李四, age=22, gender = 女], Stu [name = 赵六, age=20, gender = 女], Stu [name = 田七, age=22, gender = 女]], 男 =[Stu [name = 张三, age=20, gender = 男], Stu [name = 王五, age=18, gender = 男]]}
- // 二级分组
- @Test
- public void test21() {
- List<Stu> list = Arrays.asList(
- new Stu("张三",20,"男"),
- new Stu("李四",22,"女"),
- new Stu("王五",18,"男"),
- new Stu("赵六",20,"女"),
- new Stu("田七",22,"女")
- );
- Map<Integer, Map<String, List<Stu>>> collect = list.stream()
- .collect(Collectors.groupingBy(Stu::getAge, Collectors.groupingBy(Stu::getGender)));
- System.out.println(collect);
- }
输出:
{18={男 =[Stu [name = 王五, age=18, gender = 男]]}, 20={女 =[Stu [name = 赵六, age=20, gender = 女]], 男 =[Stu [name = 张三, age=20, gender = 男]]}, 22={女 =[Stu [name = 李四, age=22, gender = 女], Stu [name = 田七, age=22, gender = 女]]}}
- // 分区
- @Test
- public void test22() {
- List<Stu> list = Arrays.asList(
- new Stu("张三",20,"男"),
- new Stu("李四",22,"女"),
- new Stu("王五",18,"男"),
- new Stu("赵六",20,"女"),
- new Stu("田七",22,"女")
- );
- Map<Boolean, List<Stu>> collect = list.stream()
- .collect(Collectors.partitioningBy((e)->((Stu)e).getAge()>20));
- System.out.println(collect);
- }
输出:
{false=[Stu [name = 张三, age=20, gender = 男], Stu [name = 王五, age=18, gender = 男], Stu [name = 赵六, age=20, gender = 女]], true=[Stu [name = 李四, age=22, gender = 女], Stu [name = 田七, age=22, gender = 女]]}
来源: https://www.cnblogs.com/moyuduo/p/12616827.html