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

文章目录

函数式编程

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

Lambda表达式

  • 格式:

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

  • 省略规则:

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

Stream流

  • 对集合进行操作

创建流

  • 集合对象. stream()

  • 单列集合

    • 数组:

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

      • 使用 stream.of创建

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

    • 先转换为 Set<Map.Entry<String, String>>,再获取 Stream

    复制代码
      Map<String ,String > map = new HashMap<>();
      Set<Map.Entry<String, String>> entries = map.entrySet();
      Stream<Map.Entry<String, String>> stream = entries.stream();

中间操作

  • distinct

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

    • 条件过滤

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

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

      java 复制代码
      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));
  • sorted 排序

    • 先将流中类型 转换为 Comparable

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

      复制代码
        List<String > list = new ArrayList<>();
        list.add("111");
        list.add("333");
        list.add("2222");
        // forEach
        //过滤条件
        list.stream()
                .sorted()
                .forEach(integer -> System.out.println(integer));
    • 还可以传入参数

      复制代码
        list.stream()
                .map(s -> Integer.valueOf(s))
                .sorted(new Comparator<Integer>() {
                    @Override
                    public int compare(Integer o1, Integer o2) {
                        return o1-o2;
                    }
                })
                .forEach(integer -> System.out.println(integer));
  • limit:

    • 设置流的最大长度

      复制代码
        list.stream()
                .limit(2)
                .forEach(System.out::println);
  • skip:

    • 跳过前n个元素

      复制代码
        list.stream()
                .skip(2)
                .forEach(System.out::println);
  • flatMap

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

      java 复制代码
      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);
      • 输出:

      • 未简化:

        java 复制代码
        //过滤条件
        list.stream()
                .flatMap(new Function<List<String>, Stream<?>>() {
                    @Override
                    public Stream<?> apply(List<String> strings) {
                        return strings.stream();
                    }
                })
                .forEach(System.out::println);

终结操作

  • forEach

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

    • 获取流中元素的 个数

      java 复制代码
      long count = list.stream()
              .flatMap(strings -> strings.stream())
              .count();
      System.out.println(count);
  • min & max

    • 求流中最值

      • 重写比较方法:

        复制代码
          Optional<Integer> count = list.stream()
                  .flatMap(strings -> strings.stream())
                  .map(s -> Integer.valueOf(s))
                  .max(new Comparator<Integer>() {
                      @Override
                      public int compare(Integer o1, Integer o2) {
                          return o1 - o2;
                      }
                  });
          System.out.println(count);
        • 简化:

          复制代码
            Optional<Integer> count = list.stream()
                    .flatMap(strings -> strings.stream())
                    .map(s -> Integer.valueOf(s))
                    .max((o1, o2) -> o1 - o2);
            System.out.println(count);
  • collect:

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

      java 复制代码
      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);
    • 转换为set,一样:

      复制代码
        Set<String> collect = list.stream()
                .flatMap(strings -> strings.stream())
                .collect(Collectors.toSet());
        System.out.println(collect);
    • 转换为 Map集合

      复制代码
        Map<String, String> collect = list.stream()
                .flatMap(strings -> strings.stream())
                .distinct()
                .collect(Collectors.toMap(s -> s, s -> s));
        System.out.println(collect);
  • 查找:

    • anyMatch

      • 任意一个满足就为 true

        java 复制代码
        boolean b = list.stream()
                .flatMap(strings -> strings.stream())
                .anyMatch(s -> s.length() > 10);
    • allMatch

      • 所有满足才为true
    • noneMatch

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

    • findAny

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

      • 获取第一个元素

        复制代码
          List<List<String >> list = new ArrayList<>();
          list.add(Arrays.asList("111","2222"));
          list.add(Arrays.asList("1121","2222"));
          list.add(Arrays.asList("113","2222"));
          Optional<String> first = list.stream()
                  .flatMap(strings -> strings.stream())
                  .sorted()
                  .findFirst();
          first.ifPresent(System.out::println);
  • reduce归并

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

    • 原理:

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

      • 一个参数:

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

      • 0 : 初始值

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

      java 复制代码
      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. 不会影响原数据

Optional

  • 预防空指针异常

创建对象

  • 使用Optional.ofNullable

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

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

    复制代码
      String s = null;
      Optional<String> s1 = Optional.ofNullable(s);
      System.out.println(s1.orElseGet(() -> "222"));
  • orElseThrow

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

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

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

    java 复制代码
    String s = "1";
    Optional<String> s1 = Optional.ofNullable(s);
    Optional<Integer> i = s1.map(s2 -> Integer.valueOf(s2));
    i.ifPresent(System.out::println); //1

方法引用

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

高级用法

基本数据类型优化

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

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

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

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

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

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

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

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

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

    java 复制代码
    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);

并行流

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

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

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

  • 使用parallel()

    • peek中间操作

    java 复制代码
    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();
    • 打印:
相关推荐
lpfasd12313 小时前
MediaCrawler 项目深度分析
chrome·python·chrome devtools
Dxy123931021614 小时前
Python项目打包成EXE完整教程(PyInstaller实战避坑)
开发语言·python
我上去就是一套QWER然后等待复活14 小时前
Windows 清理 CC Switch 并恢复官方 Codex CLI 登录流程(完整记录)
windows
bamb0014 小时前
一个项目带你入门AI应用开发01
python
05664615 小时前
Python康复训练——常用标准库
开发语言·python·学习
骊城英雄15 小时前
基于C#+avalonia ui实现的跨平台点胶机灌胶监控控制上位机软件
开发语言·ui·c#
吾儿良辰15 小时前
一个被BCL遗忘的高性能集合:C# CircularBuffer<T>深度解析
开发语言·windows·c#
哎呦喂我去去去15 小时前
C#实现屏幕墙:同时监控多个电脑桌面(支持Windows、信创Linux、银河麒麟、统信UOS)
linux·windows·c#
昆曲之源_娄江河畔15 小时前
Python如何安装flask, pymssql
开发语言·python·flask·pymssql
Leighteen15 小时前
`try-finally` 里的 `return`:为什么 `finally` 会悄悄改掉返回值、吞掉异常
java·开发语言