Java 8 Stream 流操作 示例

Stream
在对流进行处理时,不同的流操作以级联的方式形成处理流水线。一个流水线由一个源(source),0 到多个中间操作(intermediate operation)和一个终结操作(terminal operation)完成。

1.源:源是流中元素的来源。Java 提供了很多内置的源,包括数组、集合、生成函数和 I/O 通道等。
2.中间操作:中间操作在一个流上进行操作,返回结果是一个新的流。这些操作是延迟执行的。
3.终结操作:终结操作遍历流来产生一个结果或是副作用。在一个流上执行终结操作之后,该流被消费,无法再次被消费


Java 8 支持从不同的源中创建流。

中间操作
流中间操作在应用到流上,返回一个新的流。下面列出了常用的流中间操作:

map:通过一个 Function 把一个元素类型为 T 的流转换成元素类型为 R 的流。
flatMap:通过一个 Function 把一个元素类型为 T 的流中的每个元素转换成一个元素类型为 R 的流,再 把这些转换之后的流合并。
filter:过滤流中的元素,只保留满足由 Predicate 所指定的条件的元素。
distinct:使用 equals 方法来删除流中的重复元素。
limit:截断流使其最多只包含指定数量的元素。
skip:返回一个新的流,并跳过原始流中的前 N 个元素。
sorted:对流进行排序。
peek:返回的流与原始流相同。当原始流中的元素被消费时,会首先调用 peek 方法中指定的 Consumer 实现对元素进行处理。
dropWhile:从原始流起始位置开始删除满足指定 Predicate 的元素,直到遇到第一个不满足 Predicate 的元素。
takeWhile:从原始流起始位置开始保留满足指定 Predicate 的元素,直到遇到第一个不满足 Predicate 的元素。
终结操作
  终结操作产生最终的结果。

1.forEach 和 forEachOrdered 对流中的每个元素执行由 Consumer 给定的实现。在使用 forEach 时,并没有确定的处理元素的顺序;forEachOrdered 则按照流的相遇顺序来处理元素,如果流有确定的相遇顺序的话。

2.reduce进行递归计算

3.collect生成新的数据结构

4…

部分图解:
在这里插入图片描述
在这里插入图片描述

示例代码:

public class lambdaTest1 {

    List<User> users = Arrays.asList(
            new User("张三", "北京朝阳十八里屯", 24, "15860307895", "W", Arrays.asList("g1", "g2")),
            new User("李四", "南京外城烟雨怡红院", 20, "13959606235", "W", Arrays.asList("g3", "g4", "g5")),
            new User("王五", "漳州金庭宾馆", 28, "15860301597", "M", Arrays.asList("g6")),
            new User("赵四", "厦门五缘湾", 36, "15860301547", "W", Arrays.asList("g7", "g8", "g9", "g10")),
            new User("海大富", "漳州金庭宾馆", 45, "15860312013", "M", Arrays.asList("g11", "g12", "g13")));
 }

 @Test
    public void test1() {
        //中间操作filter的作用是过滤年龄大于24的User,返回新的流
        Stream<User> userStream = users.stream().filter(user -> {
            System.out.println("过滤中:" + user.getAge());//这边拿到的是原值
            return user.getAge() > 24;//如果没有值没有大于24 就没有返回,相当于进行下一次循环
        });

        //打印流,这里才会实际执行上面的filter函数
        /**
         * 输出结果如下:
         * 过滤中:24
         * 过滤中:20
         * 过滤中:28
         * 过滤后:28
         * 过滤中:36
         * 过滤后:36
         * 过滤中:45
         * 过滤后:45
         */
        userStream.forEach(x -> System.out.println("过滤后:" + x.getAge()));

        //这里是去除list中的重复元素
        users.stream().distinct().forEach(System.out::println);
    }
 @Test
    public void test2() {
        users.stream().limit(1).filter(u -> {
            System.out.println("age:" + u.getAge());
            return (u.getAge() > 24);
        }).forEach(System.out::println);

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

        users.stream().filter(u -> {
            System.out.println("age:" + u.getAge());
            return (u.getAge() > 24);
        }).limit(1).forEach(System.out::println);

        /**
         * 输出结果:
         * age:24
         * -------------------------
         * age:24
         * age:20
         * age:28
         * User{name='王五', address='漳州', age=28, tel='15860301597', sex='M', girlfriends=[g6]}
         */

        /**
         * 中间操作是流水线形式的,即不是中间操作完成才进行终结操作,而是执行完一条中间操作接着执行一条终结操作。以此循环
         * 第二次情形,当28大于24,返回,则接着就是limit(1),还有很多大于24的对象,但是filter里面只执行完一条中间操作返回之后接着就是下一个limit操作了,这个可以验证上面的说法
         */
    }
  @Test
    public void test3() {
        /**
         * 先把users转成map,拿到所有的age,再做一个过滤操作,最后转成一个set
         * map 的作用 通过一个 Function 把一个元素类型为 T 的流转换成元素类型为 R 的流。
         */
        Set<String> collect = users.stream().map(s -> s.getAge().toString()).filter(s -> s.startsWith("2")).collect(Collectors.toSet());
        System.out.println(collect);
    }
@Test
    public void test4() {
        System.out.println("------自然排序,依赖对象自身实现Comparable");
        users.stream().map(s -> s.getAge()).sorted().forEach(System.out::println);

        System.out.println("-----定制排序,需要复写Comparator");
        //sorted的入参是Comparator接口,所以(u1,u2)->{return u1-u2;}成了Comparator接口的匿名实现
        users.stream().map(s -> s.getAge()).sorted((u1, u2) -> {
            return u1 - u2;
        }).forEach(System.out::println);

        /**
         * 倒序
         * reversed(),java8泛型推导的问题,所以如果comparing里面是非方法引用的lambda表达式就没办法直接使用reversed()
         * Comparator.reverseOrder():也是用于翻转顺序,用于比较对象(Stream里面的类型必须是可比较的)
         * Comparator. naturalOrder():返回一个自然排序比较器,用于比较对象(Stream里面的类型必须是可比较的)
         */
        System.out.println("---------------------------------------------");
        users.stream().map(s->s.getAddress()).sorted(Comparator.comparing(String::length).reversed()).forEach(System.out::println);

        System.out.println("---------------------------------------------");
        users.stream().map(s->s.getAddress()).sorted(Comparator.reverseOrder()).forEach(System.out::println);

        System.out.println("---------------------------------------------");
        users.stream().map(s->s.getAddress()).sorted(Comparator.naturalOrder()).forEach(System.out::println);
        System.out.println("---------------------------------------------");

        /**
         * thenComparing
         * 先按照首字母排序
         * 之后按照String的长度排序
         */
        users.stream().map(s->s.getAddress()).sorted(Comparator.comparing(this::com1).thenComparing(String::length)).forEach(System.out::println);
    }
    public char com1(String x){
        return x.charAt(0);
    }
/*
     * 查找与匹配
     *     allMatch:检查是否匹配所有元素
     *     anyMatch:检查是否至少匹配一个元素
     *     noneMatch:检查是否没有任何元素匹配
     *     findFirst:返回第一个元素
     *     findAny:返回当前流中的任意元素
     *  count:返回流中元素的总个数
     *  max:返回流中最大值
     *  min:返回流中最小值
     *
     */
    @Test
    public void test5() {
        boolean b1 = users.stream().allMatch(u -> u.getAddress().equals("漳州"));
        System.out.println("allMatch:" + b1);

        boolean b2 = users.stream().anyMatch(u -> u.getAddress().equals("漳州"));
        System.out.println("anyMatch:" + b2);

        boolean b3 = users.stream().noneMatch(u -> u.getAddress().equals("漳州"));
        System.out.println("noneMatch:" + b3);

        Optional<User> first = users.stream().findFirst();
        System.out.println("findFirst:" + first);

        Optional<User> user1 = users.stream().filter(u -> u.getAddress().equals("漳州")).findAny();
        System.out.println("findAny:" + user1);

        long count = users.stream().count();
        System.out.println("count:" + count);

        Optional<User> max = users.stream().max((u1, u2) -> {
            return u1.getAge() - u2.getAge();
        });
        System.out.println("max:" + max.get());

        Optional<User> min = users.stream().min((u1, u2) -> {
            return u1.getAge() - u2.getAge();
        });
        System.out.println("min:" + min.get());
    }

    /*
     * 归约:(可以理解为递归,也是终止操作)
     *     reduce 进行反复计算,如求和
     */
    @Test
    public void test6() {
        //这里0是初始值,第一次执行规约应该是0+1,其中1是第一个值
        Integer reduce = users.stream().map(s -> s.getAge()).reduce(0, (x, y) -> x + y);
        System.out.println("sum:" + reduce);

        Optional<Integer> reduce1 = users.stream().map(User::getAge).reduce(Integer::sum);
        System.out.println("sum2:" + reduce1.get());
    }
/*
     * 收集(stream的终止操作之一,forEach,reduce等也是)
     *  collect:将流转换为其他形式,接收一个collection接口的实现,用于给stream元素做汇总的方法
     */
    @Test
    public void test7() {
        //map是数据转换,将List<User> 转换为String类型的Stream。 collect把新的Stream转化为List<String>
        List<String> list1 = users.stream().map(User::getName).collect(Collectors.toList());
        list1.forEach(System.out::println);

        //这里是转换为set
        Set<String> set1 = users.stream().map(User::getName).collect(Collectors.toSet());

        //把list转为其它的数据结构,这里是hashset
        HashSet<String> hashset = users.stream().map(User::getName).collect(Collectors.toCollection(HashSet::new));

        Long count = users.stream().collect(Collectors.counting());
        System.out.println("count:" + count);

        Double averagingInt = users.stream().collect(Collectors.averagingInt(User::getAge));
        System.out.println("averagingInt:" + averagingInt);

        //按条件分组
        Map<String, List<User>> map = users.stream().collect(Collectors.groupingBy(User::getSex));
        System.out.println("collectors分组功能, map:" + map);

        //多级分组 先按sex分组,分完组之后,在每个组里面再进行分一次组
        Map<String, Map<String, List<User>>> collect = users.stream().collect(Collectors.groupingBy(
                User::getSex, Collectors.groupingBy(u -> {
                    if (u.getAge() <= 24) {
                        return "happy";
                    } else {
                        return "sad";
                    }
                })
        ));
        System.out.println("多级分组:" + collect);

        //按条件分区,true放在一组,false放在另一组
        Map<Boolean, List<User>> collect1 = users.stream().collect(Collectors.partitioningBy(u -> u.getAge() >= 24));
        System.out.println("partitioningBy:" + collect1);

        //字符串拼接
        String collect2 = users.stream().map(s -> s.getAddress()).collect(Collectors.joining(","));
        System.out.println("joining:" + collect2);


    }
@Test
    public void test8() {
        //列出年龄大于24岁的用户,并按照年龄大小降序输出用户名字
        //map的作用其实做了类型转换,在还没map之前还是User的类型,做了map则转换成User的年龄
        List<String> collect = users.stream().filter(user -> user.getAge() > 24).sorted(Comparator.comparing(User::getAge).reversed()).map(User::getName).collect(Collectors.toList());
        System.out.println(collect);

        long count = users.stream().map(s -> s.getAddress()).distinct().count();
        System.out.println("所有用户中经过去重的地址:"+count);

        System.out.println("------------------将两个流合并成一个流(合并的stream类型必须相同)----------------------------");
        Stream<String> stringStream = users.stream().map(s -> s.getName());
        Stream<String> stringStream1 = users.stream().map(s -> s.getAddress());
        /*Stream.concat(stringStream,stringStream1).distinct().forEach(System.out::println);*/
        System.out.println("---------------------------------------");
        //这边再次用到stringStream,stringStream1 的对象,要把上面用到的注释掉,或者是重新创建这两个流,不然会报错stream has already been operated upon or closed
        //stream不能被重用,一旦他被使用或使用,流将被关闭
        String collect1 = Stream.concat(stringStream, stringStream1).collect(Collectors.joining(","));
        System.out.println("两个流合并之后:"+collect1);

    }
 /**
     * flatMap 通过一个 Function 把一个元素类型为 T 的流中的每个元素转换成一个元素类型为 R 的流,再把这些转换之后的流合并。
     */

    @Test
    public void test9(){
        String[] arr1 = {"a", "b", "c", "d"};
        String[] arr2 = {"e", "f", "c", "d"};
        String[] arr3 = {"h", "j", "c", "d"};
        // Stream.of(arr1, arr2, arr3).flatMap(x -> Arrays.stream(x)).forEach(System.out::println);
        Stream.of(arr1, arr2, arr3).flatMap(Arrays::stream).forEach(System.out::println);
    }
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值