zoukankan      html  css  js  c++  java
  • JAVA8 lambda表达式权威教程!

    Java 8新特性----Stream流

    jdk8是Java 语言开发的一个主要版本,它支持函数式编程,新的 JavaScript 引擎,新的日期 API,新的Stream API 等等。今天就重点介绍一个非常重要得特性之一 lambda表达式

    一:什么是 Stream?

    Stream(流)是一个来自数据源的元素队列并支持聚合操作

    Java中的Stream并不会存储元素,而是按需计算。 数据源 流的来源。 可以是集合,数组,I/O channel, 产生器generator 等。

    聚合操作 类似SQL语句一样的操作, 比如filter, map, reduce, find, match, sorted等。 和以前的Collection操作不同,Stream操作还有两个基础的特征如下:

    • Pipelining: 中间操作都会返回流对象本身。 这样多个操作可以串联成一个管道, 如同流式风格。 这样做可以对操作进行优化, 比如延迟执行和短路。

    • 内部迭代: 以前对集合遍历都是通过Iterator或者For-Each的方式, 显式的在集合外部进行迭代, 这叫>做外部迭代。 Stream提供了内部迭代的方式, 通过访问者模式(Visitor)实现。

    二:Stream API 使用

    1:使用Stream步骤:

    (1)先产生一个流(Stream)一个数据源,获取一个流。

    (2)中间链式操作 一个中间的操作链,对数据源的数据进行处理。

    (3)产生一个新流:一个终止操作,执行中间操作,产生结果。

    注意:Stream操作是延迟执行,他们会等需要结果的时候才会执行。

    总结:

    • 中间操作常用方法有:筛选:filter 映射:map 排序:sorted提取与组合 收集:collect。

    • 终止操作:遍历:foreach 匹配:find、match 规约:reduce 聚合:max、min、count。

    2:创建Stream的方法的4种方式

        【1】Collection接口中的方法:
            default Stream<E> stream()  获取串行流
            default Stream<E> parallelStream() 获取并行流
          案例:
    
    //方式1:Collection接口的方法
    Collection collection = new ArrayList();
    Stream stream = collection.stream();
    Stream stream1 = collection.parallelStream();

    //方式2:通过Arrays中的Stream方法  数组
    IntStream stream2 = Arrays.stream(new int[]{1, 2, 3, 4, 5});

    //方式3:Stream中的of方法
    Stream<String> stream3 = Stream.of("111", "222", "333");

    //方法4:Stream中的方法  创建无限流  (结果是无线个)
    Stream<Integer> iterate = Stream.iterate(2, (x) -> x + 2);
            

    3:中间操作

    1:筛选与切片

    ① Stream filter(Predicate<?super T> predicate)返回由与此给定谓词匹配的此流的元素组成的流。 --->接收Lambda,从流中排除某些元素。

     //1:创建Stream;
      Stream<Student> stream = list.stream();

     //2:filter方法(找到年龄大于等于18岁的学生)
     Stream<Student> studentStream = stream.filter((student) -> student.getAge() >= 18);

      //3:终止操作;如果没有终止操作的话,上面的第二步中间操作不执行
       studentStream.forEach(System.out::println);
       /**
        * 注意:如果值执行1,2操作的话,不会有任何结果。
        * 验证出Steam操作是延迟的,只有进行了终止操作,才会执行中间操作!这就是所谓的延迟加载
    */

    ②Stream limit(Long maxSize) 返回由该流的元素组成的流,截断长度不能超过maxSize. 只有找到maxSize个满足条件的即可。 ---->截断流,使其元素不超过给定的数量。

      public void limitTest02() {
            //Limit方法 短路(效率增高),只要找到了2个满足条件的,后面的迭代操作就不在执行了!
            list.stream().filter(x -> {
                System.out.println("正在过滤!!");
                return x.getAge() > 18;
            }).limit(2).forEach(System.out::println);
        }

    ③Stream skip(Long n) 在丢掉流的第一个n元素后,返回由该流的n元素组成的流,如果此流包含少于n元素,那么将返回一个空流。 ---->跳过元素,返回一个扔掉了前n个元素的流。 如果流中的元素不足n个,则返回一个空流,与limit(n)互补。

    public void skipTest03() {
         //skip 方法跳过前2个满足条件的  留下后面满足条件的结果!!
         list.stream().filter(x -> {
             System.out.println("正在过滤后面满足条件的结果");
             return x.getAge() > 18;
         }).skip(2).forEach(System.out::println);
     }

    ④Stream distinct()

    注意: 自定义的类在去重的过程中必须重新hashCode和equals方法,因为distinct实现的时候底层去找这两个方法。

     public void distinctTest04() {
       //distinct 去重操作!
           list.stream().distinct().forEach(System.out::println);
       }

    ⑤ map映射:

    如果需要将流中的元素映射到另一个流中,可以使用map方法。方法签名: Stream map(Function<? super T, ? extends R> mapper); 该接口需要一个Function函数式接口参数,可以将当前流中的T类型数据转换为另一种R类型的流。 Stream流中的map方法基本使用的代码如:

    @Test
    public void testMap() {
        Stream<String> original = Stream.of("11", "22", "33");
        Stream<Integer> result = original.map(Integer::parseInt);
        result.forEach(s -> System.out.println(s + 10));
    }
    //这段代码中,map方法的参数通过方法引用,将字符串类型转换成为了int类型(并自动装箱为Integer类对象)。

    ⑥ 排序 (两种方式)

    (1)Stream sorted()返回此流元素组成的流,根据自然顺序排序。底层按照内部比较器进行排序,实现Comparable接口中的compareTo方法。

    (2)Stream sorted(Comparator<?super T>comparator) 返回由此元素组成的流,根据挺的Comparator进行顺序排序。指定顺序。 指定排序策略:底层按照外部比较器进行排序 Comparator接口一定要重新Compare方法。

    基本使用
    Stream流中的sorted方法基本使用的代码如:
    @Test
    public void testSorted() {
        // sorted(): 根据元素的自然顺序排序
        // sorted(Comparator<? super T> comparator): 根据比较器指定的规则排序
        Stream.of(33, 22, 11, 55)
                .sorted()
                .sorted((o1, o2) -> o2 - o1)
                .forEach(System.out::println);
    }
    这段代码中,sorted方法根据元素的自然顺序排序,也可以指定比较器排序。

    4:终止操作

    ①查找(find)和匹配(match)

    如果需要找到某些数据,可以使用find相关方法。方法签名:

    • Optional findFirst();
    • Optional findAny();

    Stream流中的find相关方法使用代码:

    @Test
    public void testFind() {
        Optional<Integer> first = Stream.of(5, 3, 6, 1).findFirst();
        System.out.println("first = " + first.get());

        Optional<Integer> any = Stream.of(5, 3, 6, 1).findAny();
        System.out.println("any = " + any.get());
    }

    Stream流的match方法

    如果需要判断数据是否匹配指定的条件,可以使用Match相关方法。方法签名:

    • boolean allMatch(Predicate<? super T> predicate);
    • boolean anyMatch(Predicate<? super T> predicate);
    • boolean noneMatch(Predicate<? super T> predicate); 基本使用 Stream流中的Match相关方法使用代码如:
    @Test
    public void testMatch() {
        boolean b = Stream.of(5, 3, 6, 1)
                // .allMatch(e -> e > 0); // allMatch: 元素是否全部满足条件
                // .anyMatch(e -> e > 5); // anyMatch: 元素是否任意有一个满足条件
                .noneMatch(e -> e < 0); // noneMatch: 元素是否全部不满足条件
        System.out.println("b = " + b);
    }    

    ②:遍历 foreach

    //forEach 用来遍历流中的数据
     @Test
        public void test02() {
            //案例1、2下面两种写法等同
            list.stream().map((x)->x.getName()).forEach(System.out::println);
            list.stream().map(Student::getName).forEach(System.out::println);
        }


    ③Stream流的max、min

    List<String> list13 = Arrays.asList("zhangsan","lisi","wangwu","xuwujing");
     int maxLines = list13.stream().mapToInt(String::length).max().getAsInt();
     int minLines = list13.stream().mapToInt(String::length).min().getAsInt();
     System.out.println("最长字符的长度:" + maxLines+",最短字符的长度:"+minLines);
     //最长字符的长度:8,最短字符的长度:4

    ④Stream流的count

     // Stream流提供count方法来统计其中的元素个数:long count();
      //该方法返回一个long值代表元素个数。基本使用:
    @Test
    public void testCount() {
       List<String> strList = new ArrayList<>();
       Collections.addAll(strList, "张无忌", "周芷若", "赵敏", "小昭", "杨不悔);
       System.out.println(strList.stream().count());
    }

    ⑤ 分组:groupingBy;

    当我们使用Stream流处理数据后,可以根据某个属性将数据分组:

    // 案例:
        @Test
        public void testGroup() {
            Stream<Student> studentStream = Stream.of(
                    new Student("赵丽颖", 52, 95),
                    new Student("杨颖", 56, 88),
                    new Student("迪丽热巴", 56, 55),
                    new Student("柳岩", 52, 33));
            // Map<Integer, List<Student>> map = studentStream.collect(Collectors.groupingBy(Student::getAge));
            // 将分数大于60的分为一组,小于60分成另一组
            Map<String, List<Student>> map = studentStream.collect(Collectors.groupingBy((s) -> {
                if (s.getSocre() > 60) {
                    return "及格";
                } else {
                    return "不及格";
                }
            }));
            map.forEach((k, v) -> {
                System.out.println(k + "::" + v);
            });
        }
    效果:
    不及格::[Student{name='迪丽热巴', age=56, socre=55}, Student{name='柳岩', age=52, socre=33}]
    及格::[Student{name='赵丽颖', age=52, socre=95}, Student{name='杨颖', age=56, socre=88}]

    ⑥拼接:joining

    Collectors.joining会根据指定的连接符,将所有元素连接成一个字符串。
    // 拼接
    @Test
    public void testJoining() {
        Stream<Student> studentStream = Stream.of(
                new Student("赵丽颖", 52, 95),
                new Student("杨颖", 56, 88),
                new Student("迪丽热巴", 56, 99),
                new Student("柳岩", 52, 77));
        String collect = studentStream
                .map(Student::getName)
                .collect(Collectors.joining(">_<", "^_^", "^v^"));
        System.out.println(collect);
    }
    效果:
    ^_^赵丽颖>_<杨颖>_<迪丽热巴>_<柳岩^v^

    ⑦聚合:toList,toSet,toMap;

    Stream流提供collect方法,其参数需要一个java.util.stream.Collector<T,A, R>接口对象来指定收集到哪种集合中。

    • public static Collector<T, ?, List> toList():转换为List集合。
    • public static Collector<T, ?, Set> toSet():转换为Set集合。
    • public static <T, K, U> Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper):转换为Map集合。

    下面是这两个方法的基本使用代码:

    // 将流中数据收集到集合中
    @Test
    public void testStreamToCollection() {
        Stream<String> stream = Stream.of("aa", "bb", "cc");
        // List<String> strList = stream.collect(Collectors.toList());
        // Set<String>  strSet = stream.collect(Collectors.toSet());

        ArrayList<String> arrayList = stream.collect(Collectors.toCollection(ArrayList::new));
        HashSet<String> hashSet = stream.collect(Collectors.toCollection(HashSet::new));
    }

    toMap

      @Test
        public void testCollectToMap(){
            //案例1
            List<Integer> list = Arrays.asList(1, 2, 3);
            Map<String, String> collect1 = list.stream().map(i -> i).collect(Collectors.toMap(key -> "key" + key, value -> "value:" + value));
     
            //实体list转化map id作为主键,对象作为value
            List<User> userList =new ArrayList<User>();
            UserTask userTask = new UserTask();
            userTask.setId(1);
            userTask.setName("测试");
            userList.add(userTask);
     
            Map<Integer,UserTask> taskMap = userList.stream().collect(Collectors.toMap(UserTask::getId, entity -> entity));
            System.out.println(collect1.toString());
            System.out.println(taskMap.toString());
        }
    欢迎关注我的公众号!里面可以加入微信技术交流群!
  • 相关阅读:
    高并发秒杀系统架构设计 · 抢购、微信红包、一元夺宝
    Linux服务器集群系统(一)
    keepalived+nginx双机热备+负载均衡
    kafka的一些常用命令
    基于Keepalived实现LVS双主高可用集群
    如何生动形象、切中要点地讲解 OSI 七层模型和两主机传输过程
    MyBatis动态SQL foreach标签实现批量插入
    详解Vue生命周期
    centos 解压压缩包到指定目录
    门罗币(MONERO)钱包生成教程
  • 原文地址:https://www.cnblogs.com/1ssqq1lxr/p/14778588.html
Copyright © 2011-2022 走看看