• java8函数式编程(Lambda表达式,Optional,Stream流)从入门到精通


    函数式编程

    • 不关心具体的对象,只关心数据参数和 具体操作

    Lambda表达式

    • 格式:

      • () -> {}
    • 假如接口只有一个 函数需要被重写,则可以使用 Lambda表达式来 代替 类的创建和重写

    • 省略规则:

      1. 参数类型可以省略
      2. 方法体只有一句代码时大括号return和唯一一句代码的分号可以省略
      3. 方法只有一个参数时小括号可以省略

    Stream流

    • 对集合进行操作

    创建流

    • 集合对象. stream()

    • 单列集合

      • 数组:

        • 使用 Arrays 数组工具类 来创建

        • 使用 stream.of创建

        • Integer[] arr = {1,2,3,4,5};
          Stream<Integer> stream = Arrays.stream(arr);
          Stream<Integer> stream2 = Stream.of(arr);
          
          • 1
          • 2
          • 3
    • 双列集合:

      • 先转换为 Set>,再获取 Stream

      • Map map = new HashMap<>();
        Set> entries = map.entrySet();
        Stream> stream = entries.stream();
        
        • 1
        • 2
        • 3

    中间操作

    • distinct

      • 去重
        • 依靠 Objec.equals方法
          • 不重写是 地址相同
    • filter(条件)

      • 条件过滤

        • list.stream()
                  .distinct() //过滤重复元素
                  .filter(s -> s.length() <=3)
                  .forEach(s -> System.out.println(s));
          
          • 1
          • 2
          • 3
          • 4
    • map

      • 转化集合中每个元素的类型:

        • List<String > list = new ArrayList<>();
          list.add("111");
          list.add("111");
          list.add("2222");
          // forEach
          //过滤条件
          list.stream()
                  .map(s -> Integer.valueOf(s))
                  .forEach(integer -> System.out.println(integer));
          
          • 1
          • 2
          • 3
          • 4
          • 5
          • 6
          • 7
          • 8
          • 9
    • sorted 排序

      • 先将流中类型 转换为 Comparable

      • 如果是空参,自定义类型需要实现Comparable接口

        • List list = new ArrayList<>();
          list.add("111");
          list.add("333");
          list.add("2222");
          // forEach
          //过滤条件
          list.stream()
                  .sorted()
                  .forEach(integer -> System.out.println(integer));
          
          • 1
          • 2
          • 3
          • 4
          • 5
          • 6
          • 7
          • 8
          • 9
      • 还可以传入参数

        • list.stream()
                  .map(s -> Integer.valueOf(s))
                  .sorted(new Comparator() {
                      @Override
                      public int compare(Integer o1, Integer o2) {
                          return o1-o2;
                      }
                  })
                  .forEach(integer -> System.out.println(integer));
          
          • 1
          • 2
          • 3
          • 4
          • 5
          • 6
          • 7
          • 8
          • 9
    • limit:

      • 设置流的最大长度

        • list.stream()
                  .limit(2)
                  .forEach(System.out::println);
          
          • 1
          • 2
          • 3
    • skip:

      • 跳过前n个元素

        • list.stream()
                  .skip(2)
                  .forEach(System.out::println);
          
          • 1
          • 2
          • 3
    • flatMap

      • 将流中一个元素 转换成 流元素

        • List<List<String >> list = new ArrayList<>();
          list.add(Arrays.asList("111","2222"));
          list.add(Arrays.asList("1121","2222"));
          list.add(Arrays.asList("113","2222"));
          // forEach
          //过滤条件
          list.stream()
                  .flatMap(strings -> strings.stream())
                  .forEach(System.out::println);
          
          • 1
          • 2
          • 3
          • 4
          • 5
          • 6
          • 7
          • 8
          • 9
          • 输出:

            • image-20231113143845889
          • 未简化:

            • //过滤条件
              list.stream()
                      .flatMap(new Function<List<String>, Stream<?>>() {
                          @Override
                          public Stream<?> apply(List<String> strings) {
                              return strings.stream();
                          }
                      })
                      .forEach(System.out::println);
              
              • 1
              • 2
              • 3
              • 4
              • 5
              • 6
              • 7
              • 8
              • 9

    终结操作

    • forEach

      • 对流中元素进行遍历操作
    • count:

      • 获取流中元素的 个数

        • long count = list.stream()
                  .flatMap(strings -> strings.stream())
                  .count();
          System.out.println(count);
          
          • 1
          • 2
          • 3
          • 4
    • min & max

      • 求流中最值

        • 重写比较方法:

          • Optional count = list.stream()
                    .flatMap(strings -> strings.stream())
                    .map(s -> Integer.valueOf(s))
                    .max(new Comparator() {
                        @Override
                        public int compare(Integer o1, Integer o2) {
                            return o1 - o2;
                        }
                    });
            System.out.println(count);
            
            • 1
            • 2
            • 3
            • 4
            • 5
            • 6
            • 7
            • 8
            • 9
            • 10
            • 简化:

              • Optional count = list.stream()
                        .flatMap(strings -> strings.stream())
                        .map(s -> Integer.valueOf(s))
                        .max((o1, o2) -> o1 - o2);
                System.out.println(count);
                
                • 1
                • 2
                • 3
                • 4
                • 5
    • collect:

      • 转换为list,使用 集合类中的 tolist方法:

        • List<List<String >> list = new ArrayList<>();
          list.add(Arrays.asList("111","2222"));
          list.add(Arrays.asList("1121","2222"));
          list.add(Arrays.asList("113","2222"));
          List<String> collect = list.stream()
                  .flatMap(strings -> strings.stream())
                  .collect(Collectors.toList());
          System.out.println(collect);
          
          • 1
          • 2
          • 3
          • 4
          • 5
          • 6
          • 7
          • 8
      • 转换为set,一样:

        • Set collect = list.stream()
                  .flatMap(strings -> strings.stream())
                  .collect(Collectors.toSet());
          System.out.println(collect);
          
          • 1
          • 2
          • 3
          • 4
      • 转换为 Map集合

        • Map collect = list.stream()
                  .flatMap(strings -> strings.stream())
                  .distinct()
                  .collect(Collectors.toMap(s -> s, s -> s));
          System.out.println(collect);
          
          • 1
          • 2
          • 3
          • 4
          • 5
    • 查找:

      • anyMatch

        • 任意一个满足就为 true

          • boolean b = list.stream()
                    .flatMap(strings -> strings.stream())
                    .anyMatch(s -> s.length() > 10);
            
            • 1
            • 2
            • 3
      • allMatch

        • 所有满足才为true
      • noneMatch

        • 都不满足才为 true
    • 匹配:

      • findAny

        • 获取任意一个满足条件的 元素
      • findFirst

        • 获取第一个元素

          • List> list = new ArrayList<>();
            list.add(Arrays.asList("111","2222"));
            list.add(Arrays.asList("1121","2222"));
            list.add(Arrays.asList("113","2222"));
            Optional first = list.stream()
                    .flatMap(strings -> strings.stream())
                    .sorted()
                    .findFirst();
            first.ifPresent(System.out::println);
            
            • 1
            • 2
            • 3
            • 4
            • 5
            • 6
            • 7
            • 8
            • 9
    • reduce归并

      • 对流中数据按照指定的计算方式计算出一个结果

      • 原理:

        • 两个参数的重载形式内部的计算方式如下:

          • image-20231113151352426
        • 一个参数:

          • 把第一个参数 作为 初始化值
          • image-20231113152846836
      • 使用:

        • 0 : 初始值

        • (result, integer2) -> result + integer2 执行的操作

        • List<List<String >> list = new ArrayList<>();
          list.add(Arrays.asList("111","2222"));
          list.add(Arrays.asList("1121","2222"));
          list.add(Arrays.asList("113","2222"));
          Integer reduce = list.stream()
                  .flatMap(strings -> strings.stream())
                  .map(s -> Integer.valueOf(s))
                  .reduce(0, (result, integer2) -> result + integer2);
          
          • 1
          • 2
          • 3
          • 4
          • 5
          • 6
          • 7
          • 8

    注意事项

    1. 惰性求值
      • 没有终结操作,中间操作不会执行
    2. 流是一次性的
      • 一个流只能执行一次 终结操作
    3. 不会影响原数据

    Optional

    • 预防空指针异常

    创建对象

    • 使用Optional.ofNullable

      • String s = new String("1");
        Optional<String> s1 = Optional.ofNullable(s);
        s1.ifPresent(s2 -> System.out.println(s2));
        
        • 1
        • 2
        • 3
    消费值
    • s1.ifPresent(s2 -> System.out.println(s2));
      
      • 1
    获取值
    • orElseGet

      • 为空则使用重写的 返回值

      • String s = null;
        Optional s1 = Optional.ofNullable(s);
        System.out.println(s1.orElseGet(() -> "222"));
        
        • 1
        • 2
        • 3
    • orElseThrow

      • 为空,则抛出异常
    过滤
    • filter

      • 假如不满足过滤条件,则返回 Optional.empty

        • String s = "null";
          Optional<String> s1 = Optional.ofNullable(s);
          Optional<String> s2 = s1.filter(s3 -> s3.length() < 2);
          System.out.println(s2); //打印 Optional.empty
          
          • 1
          • 2
          • 3
          • 4
    判断
    • isPresent
      • 判断是否存在
    数据转换
    • 使用map 进行 Optional类型的转换

      • String s = "1";
        Optional<String> s1 = Optional.ofNullable(s);
        Optional<Integer> i = s1.map(s2 -> Integer.valueOf(s2));
        i.ifPresent(System.out::println); //1
        
        • 1
        • 2
        • 3
        • 4

    方法引用

    • 在使用 Lambda 表达式的时候,如果方法体中只有一个方法 的调用话,就可以使用 类名或者对象名::方法名 来简化

    高级用法

    基本数据类型优化

    • 我们之前用到的很多Stream的方法由于都使用了泛型。

    • 所以涉及到的参数和返回值都是引用数据类型。

    • 即使我们操作的是整数小数,但是实际用的都是他们的包装类

    • JDK5中引入的自动装箱和自动拆箱让我们在使用对应的包装类时就好像使用基本数据类型一样方便。

    • 但是你一定要知道装箱和拆箱肯定是要消耗时间的。

    • 虽然这个时间消耗很下。但是在大量的数据不断的重复装箱拆箱的时候,你就不能无视这个时间损耗了。

    • 所以为了让我们能够对这部分的时间消耗进行优化。

    • Stream还提供了很多专门针对基本数据类型的方法。

    • 例如: mapToInt,mapToLong,mapToDouble,flatMapTolnt,flatMapToDouble等。

      • List<List<String >> list = new ArrayList<>();
        list.add(Arrays.asList("111","2222"));
        list.add(Arrays.asList("1121","2222"));
        list.add(Arrays.asList("113","2222"));
        list.stream()
                .flatMap(strings -> strings.stream())
                .mapToInt(s -> Integer.valueOf(s))
                .forEach(System.out::println);
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8

    并行流

    • 当流中有大量元素时,我们可以使用并行流去提高操作的效率。其实并行流就是把任务分配给多个线程去完全。

    • 如果我们自己去用代码实现的话其实会非常的复杂,并且要求你对并发编程有足够的理解和认识。

    • 而如果我们使用Stream的话,我们只需要修改一个方法的调用就可以使用并行流来帮我们实现,从而提高效率。

    • 使用parallel()

      • peek中间操作

      • List<List<String >> list = new ArrayList<>();
        list.add(Arrays.asList("111","2222"));
        list.add(Arrays.asList("1121","2222"));
        list.add(Arrays.asList("113","2222"));
        OptionalInt first = list.stream()
            .parallel()
            .flatMap(strings -> strings.stream())
            .mapToInt(s -> Integer.valueOf(s))
            .peek(i -> System.out.println(i + ":" + Thread.currentThread().getName()))
            .findFirst();
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 打印:
          • image-20231113163806329
  • 相关阅读:
    Apache Flink开发时选择Java还是Scala作为编程语言
    阿里云全面降价,释放了什么信号?
    Redis 概述、Win 10 下载安装、redis.conf 配置文件详解
    【SpringBoot】YAML 配置文件
    Java编程实践:使用面向对象编程(OOP)概念构建简单的国际象棋游戏
    【Redis】缓存击穿的产生情况&解决方案
    一周吃透Java面试八股文(2023最新整理
    基于FTP协议的文件上传与下载
    Python进行时间序列平稳性检验(ADF Test)
    如何录制微课?教师必看
  • 原文地址:https://blog.csdn.net/yin_ming_hui/article/details/134380851