学会-Java8 Stream

131 阅读6分钟

Stream

遍历数据集的高级迭代器。使用StreamApi让代码:

  1. 声明式:更简洁,更易读;
  2. 可复合:更灵活;
  3. 可并行:性能更好;

使用流

流的使用一般包括三件事:

  1. 一个数据源(如集合)来执行一个查询;
  2. 一个中间操作链,形成一条流的流水线;
  3. 一个终端操作,执行流水线,并能生成结果;

流操作

创建操作

创建流

  • 集合

    List<Employee> employees = EmployeeData.getEmployees();
    //        default Stream<E> stream() : 返回一个顺序流
    Stream<Employee> stream = employees.stream();
    //        default Stream<E> parallelStream() : 返回一个并行流
    Stream<Employee> parallelStream = employees.parallelStream();
    
  • 数组

     int[] arr = new int[]{1,2,3,4,5,6}
    //调用Arrays类的static <T> Stream<T> stream(T[] array): 返回一个流
     IntStream stream = Arrays.stream(arr);
    
  • stream的of()

    Stream<Integer> stream = Stream.of(123456);
    
  • 文件流

    Java中用于处理文件等I/O操作的NIO API(非阻塞I/O)已更新,以便利用StreamAPI。java.nio.file.Files中的很多静态方法都会返回一个流。例如,一个很有用的方法是Files.lines,它会返回一个由指定文件中的各行构成的字符串流。

    Files.lines得到一个流,其中的每个元素都是给定文件中的一行

    Stream<String> lines = Files.lines(Paths.get("/comprehensive-code/aaaa.txt")
    
  • 无限流

    • 迭代 Stream.iterate

       Stream.iterate(0,n -> n+2).limit(5).forEach(System.out::println);
      
    • 生成 Stream.generate

       Stream.generate(Math::random).limit(10).forEach(System.out::println);
      
    • 由iterate和generate产生的流会用给定的函数按需创建值,因此可以无穷无尽地计算下去!一般来说,应该使用limit(n)来对这种流加以限制,以避免打印无穷多个值。

中间操作

可以连接起来的流操作

筛选

  • filter过滤操作

  • distinct去重操作

    List<Employee> list = EmployeeData.getEmployees();
    //        filter(Predicate p)——接收 Lambda , 从流中排除某些元素。
    Stream<Employee> stream = list.stream();
    //练习:查询员工表中薪资大于7000的员工信息
    stream.filter(e -> e.getSalary() > 7000).forEach(System.out::println);
    

切片

  • limit

    //        limit(n)——截断流,使其元素不超过给定数量。
    list.stream().limit(3).forEach(System.out::println);
    
  • skip

    //        skip(n) —— 跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素不足 n 个,则返回一个空流。与 limit(n) 互补
    list.stream().skip(3).forEach(System.out::println);
    
  • takeWhile(Java 9方法)遭遇第一个不符合要求的元素时停止处理

  • dropWhile(Java 9方法)遭遇第一个符合要求的元素时停止处理

映射

  • map

    //        map(Function f)——接收一个函数作为参数,将元素转换成其他形式或提取信息,该函数会被应用到每个元素上,并将其映射成一个新的元素。
    List<String> list = Arrays.asList("aa""bb""cc""dd");
    list.stream().map(str -> str.toUpperCase()).forEach(System.out::println);
    
  • flatmap

    //        flatMap(Function f)——接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流。
    Stream<String> stringStream = Stream.of("aaaaa""vvvvv""dddddd""avd");
    List<String> collect = stringStream
            .map(string -> string.split(""))
            .flatMap(Arrays::stream).collect(Collectors.toList());
    System.out.println(collect);
    

排序

  • sorted

    //        sorted()——自然排序
    List<Integer> list = Arrays.asList(12436534870, -987);
    list.stream().sorted().forEach(System.out::println);
    //        sorted(Comparator com)——定制排序
    
    List<Employee> employees = EmployeeData.getEmployees();
    employees.stream().sorted( (e1,e2) -> {
    
     int ageValue = Integer.compare(e1.getAge(),e2.getAge());
     if(ageValue != 0){
         return ageValue;
     }else{
         return -Double.compare(e1.getSalary(),e2.getSalary());
     }
    
    }).forEach(System.out::println);
    

终止操作

关闭流的操作

查找

  • findAny

    //        findFirst——返回第一个元素
    Optional<Employee> employee = employees.stream().findFirst();
    
  • findFirst

    //        findAny——返回当前流中的任意元素
    Optional<Employee> employee1 = employees.parallelStream().findAny();
    

匹配

  • anyMatch

    //         anyMatch(Predicate p)——检查是否至少匹配一个元素。
    //         练习:是否存在员工的工资大于 10000
    boolean anyMatch = employees.stream().anyMatch(e -> e.getSalary() > 10000);
    
  • allMatch

    //        allMatch(Predicate p)——检查是否匹配所有元素。
    //          练习:是否所有的员工的年龄都大于18
    boolean allMatch = employees.stream().allMatch(e -> e.getAge() > 18);
    
  • noneMatch

    //          noneMatch(Predicate p)——检查是否没有匹配的元素。
    //          练习:是否存在员工姓“雷”
    boolean noneMatch = employees.stream().noneMatch(e -> e.getName().startsWith("雷"));
    

求和 最大和最小值

  • count
// count——返回流中元素的总个数
long count = employees.stream().filter(e -> e.getSalary() > 5000).count();
  • max min
//        max(Comparator c)——返回流中最大值
//        练习:返回最高的工资:
Stream<Double> salaryStream = employees.stream().map(e -> e.getSalary());
Optional<Double> maxSalary = salaryStream.max(Double::compare);
System.out.println(maxSalary);
//        min(Comparator c)——返回流中最小值
//        练习:返回最低工资的员工
Optional<Employee> employee = employees.stream().min((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));
System.out.println(employee);

归约

  • redue

    //        reduce(T identity, BinaryOperator)——可以将流中元素反复结合起来,得到一个值。返回 T
    //        练习1:计算1-10的自然数的和
    List<Integer> 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);
    
    
    //        reduce(BinaryOperator) ——可以将流中元素反复结合起来,得到一个值。返回 Optional<T>
    //        练习2:计算公司所有员工工资的总和
    List<Employee> employees = EmployeeData.getEmployees();
    Stream<Double> salaryStream = employees.stream().map(Employee::getSalary);
    Optional<Double> sumMoney = salaryStream.reduce(Double::sum);
    // Optional<Double> sumMoney = salaryStream.reduce((d1,d2) -> d1 + d2);
    System.out.println(sumMoney.get());
    

收集

collect方法,主要使用收集器Collector

数值流

减少装箱拆箱操作,Stream API还提供了原始类型流特化,专门支持处理数值流的方法。IntStream、DoubleStream和LongStream

  • 映射到数值流

    • mapToInt
    • mapToDouble
    • mapToLong
  • 转换回对象流

    • boxed
  • 默认值OptionalInt

    Stream<Integer> integerStream = Stream.of(123456);
    OptionalInt max = integerStream.mapToInt(Integer::intValue).max();
    System.out.println(max.orElse(1));