学习笔记-Java8新特性-第四节-StreamAPI

StreamAPI

  • 利用StreamAPI可以像流水线一样操作处理数据源(数组、集合……)

  • Stream自己不会存储元素

  • Stream不会改变数据源,而是会返回一个持有处理结构的新Stream

  • Steam操作时延迟执行的,他们会等到需要结果的时候才执行

    • 称为惰性求值

Stream操作的三个步骤

  • 创建Stream

    • 一个数据源(如:集合、数组),获取一个流
  • 中间操作

    • 一个中间操作链,对数据源的数据进行处理
  • 终止操作

    • 一个终止操作,执行中间操作链,并产生结果

创建Stream

  • 通过Collection系列集合提供的stream()或paralleStream()

    • List list = new ArrayList<>();
      Stream stream = list.stream();
  • 通过Arrays中的静态方法stream()获取数组流

    • Employee[] employees = new Employee[10];
      Stream stream1 = Arrays.stream(employees);
  • 通过Stream类中的静态方法of()

    • Stream stream2 = Stream.of("aa", "bb", "cc");
  • 创建无限流

    • //1.迭代
      //获取正偶数的无限流
      Stream stream3 = Stream.iterate(0, (x) -> x + 2);
      stream3.limit(10).forEach(System.out::println);

      //2.生成
      //获取随机数
      Stream.generate(() -> Math.random())
      .limit(5)
      .forEach(System.out::println);

中间操作

筛选与切片

  • filter——接收断言型Lambda,从流中排除某些元素

    • public void test1() {
      //过滤,保留年龄大于35的员工
      employees.stream()
      .filter((e) -> {
      System.out.println("StreamAPI的中间操作");
      return e.getAge() > 35;
      })
      .forEach(System.out::println);
      }
  • limit——截断流,使其元素不超过给定数量

    • public void test2() {
      //截取,保留2个
      employees.stream()
      .limit(2)
      .forEach(System.out::println);
      }
  • skip——跳过,扔掉前n个元素

    • public void test3() {
      //跳过,扔掉前2个
      employees.stream()
      .skip(2)
      .forEach(System.out::println);
      }
  • distinct——去重,通过hashCode()和equals()判断是否相等

    • @Test
      public void test4() {
      //去重
      employees.stream()
      .distinct()
      .forEach(System.out::println);
      }

映射

  • map——接受一个Lambda,将元素转换成其他形式或提取信息

    • 接收一个函数作为参数,该函数会被应用到每个元素上,并映射成一个新的元素

    • public void test5() {
      List list = Arrays.asList("aa", "bb", "ccc", "ddd", "eee");

      list.stream()
      .map((s) -> s.toUpperCase())
      .forEach(System.out::println);

      System.out.println("_________________");

      employees.stream()
      .map(Employee::getName)
      .forEach(System.out::println);

      }

  • flatMap

    • 接收一个函数作为参数,将流中的每一个值都换成另一个流,然后把所有流连接成一个流

    • public void test6() {
      List list = new ArrayList<>();
      list.add("aaa");
      list.add("bbb");

      list.stream()
      //返回值为Stream<Stream>
      .map(TestStreamAPI2::filterCharacter)
      .forEach((characterStream) -> {
      characterStream.forEach(System.out::println);
      });

      System.out.println("------------------------");

      list.stream()
      //返回值为Stream
      .flatMap(TestStreamAPI2::filterCharacter)
      .forEach(System.out::println);
      }

      public static Stream filterCharacter(String str) {
      List list = new ArrayList<>();

      for(Character ch : str.toCharArray()) {
      list.add(ch);
      }

      return list.stream();
      }

排序

  • sorted()——自然排序(Comparable)

  • sorted(Comparator cmp)——定制排序

  • public void test7() {
    List list = Arrays.asList("bbb", "aaa", "ddd", "eee", "ccc");

    list.stream()
    .sorted()
    .forEach(System.out::println);

    System.out.println("---------------------");

    employees.stream()
    .sorted((e1, e2) -> {
    if(e1.getAge() == e2.getAge()) {
    return e1.getName().compareTo(e2.getName());
    } else {
    return Integer.compare(e1.getAge(), e2.getAge());
    }
    })
    .forEach(System.out::println);

    }

终止操作

查找与匹配

  • allMatch——检查是否匹配所有元素

  • anyMatch——检查是狗至少匹配一个元素

  • noneMatch——检查是否没有匹配所有元素

  • findFirst——返回第一个元素

  • findAny——返回当前流中的任意元素

    • List employees = Arrays.asList(
      new Employee("张三", 18, 9999.99, Employee.Status.FREE),
      new Employee("李四", 38, 5555.55, Employee.Status.BUSY),
      new Employee("王五", 50, 6666.66, Employee.Status.VOCATION),
      new Employee("赵六", 16, 3333.33, Employee.Status.FREE),
      new Employee("田七", 8, 7777.77, Employee.Status.BUSY)
      );

      @Test
      public void test1() {
      boolean b1 = employees.stream()
      .allMatch((e) -> e.getStatus().equals(Employee.Status.BUSY));
      System.out.println(b1);

      boolean b2 = employees.stream()
      .anyMatch((e) -> e.getStatus().equals(Employee.Status.BUSY));
      System.out.println(b2);

      boolean b3 = employees.stream()
      .noneMatch((e) -> e.getStatus().equals(Employee.Status.BUSY));
      System.out.println(b3);

      Optional first = employees.stream()
      .sorted(Comparator.comparingDouble(Employee::getSalary))
      .findFirst();
      System.out.println(first);

      Optional any = employees.parallelStream()
      .filter((e) -> e.getStatus().equals(Employee.Status.BUSY))
      .findAny();
      System.out.println(any);

      }

  • count——返回流中元素的总个数

  • max——返回流中的最大值

  • min——返回流中的最小值

    • public void test2() {
      long count = employees.stream()
      .count();
      System.out.println(count);

      Optional max = employees.stream()
      .max(Comparator.comparingDouble(Employee::getSalary));
      System.out.println(max);

      Optional min = employees.stream()
      .map(Employee::getSalary)
      .min(Double::compare);
      System.out.println(min);
      }

规约

  • reduce(T identity, BinaryOperator) / reduce(BinaryOperator)

    • 将流中的元素反复结合起来,得到一个值

    • identity代表一个初始值

    • public void test3() {
      List list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

      Integer sum = list.stream()
      .reduce(0, Integer::sum);
      System.out.println(sum);

      System.out.println("-------------------");

      Optional op = employees.stream()
      .map(Employee::getSalary)
      .reduce(Double::sum);
      System.out.println(op.get());
      }

收集

  • collect——将流转换为其他形式

    • 接收一个Collector接口的实现

      • 使用对应的静态类Collectors提供的静态方法,可以方便地创建Collector实例
    • 用于给Stream中元素做汇总的方法

    • public void test4() {
      List list = employees.stream()
      .map(Employee::getName)
      .collect(Collectors.toList());
      list.forEach(System.out::println);

      System.out.println("------------------");

      Set set = employees.stream()
      .map(Employee::getName)
      .collect(Collectors.toSet());
      set.forEach(System.out::println);

      System.out.println("------------------");

      HashSet<Employee.Status> hashSet = employees.stream()
      .map(Employee::getStatus)
      .collect(Collectors.toCollection(HashSet::new));
      hashSet.forEach(System.out::println);

      }

    • public void test5() {
      Double avg = employees.stream()
      .collect(Collectors.averagingDouble(Employee::getSalary));
      System.out.println(avg);

      System.out.println("_________________________");

      Double sum = employees.stream()
      .collect(Collectors.summingDouble(Employee::getSalary));

      }

    • @Test
      public void test6() {
      // 分组
      Map<Employee.Status, List> collect = employees.stream()
      .collect(Collectors.groupingBy(Employee::getStatus));
      System.out.println(collect);

      // 多级分组
      Map<Employee.Status, Map<String, List>> collect1 = employees.stream()
      .collect(Collectors.groupingBy(Employee::getStatus, Collectors.groupingBy((e) -> {
      if (e.getAge() <= 35) {
      return "青年";
      } else if (e.getAge() <= 50) {
      return "中年";
      } else {
      return "老年";
      }
      })));
      System.out.println(collect1);

      }

    • public void test7() {
      // 分区
      Map<Boolean, List> collect = employees.stream()
      .collect(Collectors.partitioningBy((e) -> e.getSalary() > 5000));
      System.out.println(collect);
      }

    • public void test8() {
      // 统计
      DoubleSummaryStatistics statistics = employees.stream()
      .collect(Collectors.summarizingDouble(Employee::getSalary));

      System.out.println(statistics.getSum());
      System.out.println(statistics.getAverage());
      System.out.println(statistics.getMax());
      }

    • public void test9() {
      // 字符串处理
      String collect = employees.stream()
      .map(Employee::getName)
      .collect(Collectors.joining(",", "=", "="));
      System.out.println(collect);
      // =张三,李四,王五,赵六,田七=
      }

并行流与顺序流

  • 并行流就是把一个内容分成多个数据块,并用不同的线程分别处理每个数据块的流

  • 底层使用到了Fork/Join框架

    • 使用了工作窃取模式

      • 将小任务分成了数个线程队列

      • 当某个线程队列处理完成后,会从其他没有完成的线程队列末尾偷取任务

Fork/Join

  • 可以使用parallel方法将流切换到并行模式

  • 提高工作效率

posted @ 2023-05-21 23:10  0Andl0  阅读(74)  评论(0)    收藏  举报