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);
        
  • 双列集合:

    • 先转换为 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(条件)

    • 条件过滤

      • list.stream()
                .distinct() //过滤重复元素
                .filter(s -> s.length() <=3)
                .forEach(s -> System.out.println(s));
        
  • 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));
        
  • 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

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

      • 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);
        
        • 输出:

          • image-20231113143845889
        • 未简化:

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

终结操作

  • forEach

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

    • 获取流中元素的 个数

      • 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方法:

      • 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

        • 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归并

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

    • 原理:

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

        • 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. 不会影响原数据

Optional

  • 预防空指针异常

创建对象

  • 使用Optional.ofNullable

    • String s = new String("1");
      Optional<String> s1 = Optional.ofNullable(s);
      s1.ifPresent(s2 -> System.out.println(s2));
      
消费值
  • 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

      • 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类型的转换

    • 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等。

    • 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中间操作

    • 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();
      
      • 打印:
        • image-20231113163806329
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

雪芙花

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值