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();
    • 打印:
相关推荐
NiNg_1_2343 分钟前
机器学习之Python中Scikit-Learn(sklearn)入门
python·机器学习·scikit-learn
曳渔5 分钟前
Java-数据结构-二叉树-习题(三)  ̄へ ̄
java·开发语言·数据结构·算法·链表
你可以自己看22 分钟前
python中函数式编程与高阶函数,装饰器与生成器,异常处理与日志记录以及项目实战
服务器·开发语言·python
gopher951139 分钟前
go语言 数组和切片
开发语言·golang
ymchuangke40 分钟前
线性规划------ + 案例 + Python源码求解(见文中)
开发语言·python
gopher951141 分钟前
go语言Map详解
开发语言·golang
鸠摩智首席音效师44 分钟前
如何设置 Django 错误邮件通知 ?
python·django
Python私教44 分钟前
Go语言现代web开发15 Mutex 互斥锁
开发语言·前端·golang
优雅一只猫1 小时前
Pybullet 安装过程
python
小电玩1 小时前
JAVA SE8
java·开发语言