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();
    • 打印:
相关推荐
封步宇AIGC18 分钟前
量化交易系统开发-实时行情自动化交易-Okex K线数据
人工智能·python·机器学习·数据挖掘
慕舟舟20 分钟前
Windows密码的网络认证---基于挑战响应认证的NTLM协议
windows·网络安全
封步宇AIGC20 分钟前
量化交易系统开发-实时行情自动化交易-Okex交易数据
人工智能·python·机器学习·数据挖掘
小爬虫程序猿22 分钟前
如何利用Python解析API返回的数据结构?
数据结构·数据库·python
波点兔24 分钟前
【部署glm4】属性找不到、参数错误问题解决(思路:修改模型包版本)
人工智能·python·机器学习·本地部署大模型·chatglm4
一点媛艺3 小时前
Kotlin函数由易到难
开发语言·python·kotlin
姑苏风3 小时前
《Kotlin实战》-附录
android·开发语言·kotlin
奋斗的小花生4 小时前
c++ 多态性
开发语言·c++
魔道不误砍柴功4 小时前
Java 中如何巧妙应用 Function 让方法复用性更强
java·开发语言·python
闲晨4 小时前
C++ 继承:代码传承的魔法棒,开启奇幻编程之旅
java·c语言·开发语言·c++·经验分享