打赏
Fork me on GitHub

Java8 新特性 - Stream

Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据。

Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。

Stream API可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。

这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。

元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果。

+--------------------+       +------+   +------+   +---+   +-------+
| stream of elements +-----> |filter+-> |sorted+-> |map+-> |collect|
+--------------------+       +------+   +------+   +---+   +-------+

 一、Stream 的三个操作步骤

  • 1. 创建Stream
  • 2. 中间操作
  • 3. 终止操作(终端操作)

  1.)创建 Stream 测试代码如下:

package com.xq.stream;

import com.xq.design.model.Employee;
import org.junit.jupiter.api.Test;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;

public class TestStreamAPI1 {
    //创建 Stream
    @Test
    public void test1(){
        //1. 可以通过 Collection 系列集合提供的 stream() 或 parallelStream()
        List<String> list = new ArrayList<>();
        Stream<String> stream1 = list.stream();

        //2. 通过 Arrays 中的静态方法 stream() 获取数组
        Employee[] emps = new Employee[10];
        Stream<Employee> streame =  Arrays.stream(emps);

        //3. 通过 Stream 类中的静态方法 of()
        Stream<String> steam3 = Stream.of("aa","bb","cc");

        //4. 创建无线流
        // - 迭代
        Stream<Integer> stream4 = Stream.iterate(0,(x) -> x + 2);
        stream4.limit(10).forEach(System.out::println);
        // - 生成
        Stream.generate(() -> Math.random())
                .limit(5)
                .forEach(System.out::println);
    }

}
TestStreamAPI1 

2)中间操作

  • 筛选与切片
  1. filter —— 接受 Lambda ,从流中抛出某些元素。
  2. limit --- 截断流,使其元素不超过给定数量。
  3. skip(n) --- 跳过元素,返回一个扔掉了前 n 个元素的流。 若流中元素不足 n 个,则返回一个空流。与 limit(n) 互补
  4. distinct --- 筛选,通过流所生成元素的 hashCode() 和 equals() 去除重复元素
  • 映射
  1. map --- 接收 Lambda ,将元素转换成其他形式或提取信息。接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
  2. flatMap --- 接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有的流连接成一个流。
  • 排序
  1. sorted() ---- 自然排序(Comparable)
  2. sorted(Comparator com) ---- 定制排序

测试代码如下:

package com.xq.stream;

import com.xq.design.model.Employee;
import org.junit.jupiter.api.Test;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Stream;

/**
 * 中间操作
 */
public class TestStreamAPI2 {
    List<Employee> employees = Arrays.asList(
            new Employee("张三",18,9999.99),
            new Employee("李四",58,8888.88),
            new Employee("王五",26,5555.55),
            new Employee("赵六",36,6666.66),
            new Employee("田七",12,3333.33),
            new Employee("赵六",36,6666.66),
            new Employee("赵六",36,6666.66)
    );
    
    //内部迭代:迭代操作由 Stream API 完成
    @Test
    public void test1(){
        // 中间操作:  不会执行任何操作
        Stream stream = employees.stream()
                .filter((e) -> {
                    System.out.println("Stream API 的中间操作");
                    return e.getAge() > 35;
                });
        // 终止操作:一次性执行全部内容,即“惰性求值”
        stream.forEach(System.out::println);
    }

    //外部迭代
    @Test
    public void test2(){
        Iterator<Employee> it = employees.iterator();
        while (it.hasNext()){
            System.out.println(it.next());
        }
    }
    
    /**
     *  筛选与切片
     *  filter —— 接受 Lambda ,从流中抛出某些元素。
     *  limit  --- 截断流,使其元素不超过给定数量。
     *  skip(n) --- 跳过元素,返回一个扔掉了前 n 个元素的流。 若流中元素不足 n 个,则返回一个空流。与 limit(n) 互补
     *  distinct --- 筛选,通过流所生成元素的 hashCode() 和 equals() 去除重复元素
     */
    @Test
    public void test3(){
        employees.stream()
                .filter((e) ->{
                    System.out.println("短路!");
                    return e.getSalary() > 7000;
                })
                .limit(2)
                .forEach(System.out::println);
    }
    
    @Test
    public void test4(){
       employees.stream()
               .filter((e) -> e.getSalary() > 5000)
               .skip(2)
               .forEach(System.out::println);
    }
    
    @Test
    public void test5(){
        employees.stream()
                .filter((e) -> e.getSalary() > 5000)
                .distinct()
                .forEach(System.out::println);
    }
    
    /**
     * 映射
     * map --- 接收 Lambda ,将元素转换成其他形式或提取信息。接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
     * flatMap --- 接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有的流连接成一个流。
     */
    @Test
    public void test6(){
        List<String> list = Arrays.asList("aaa","bbb","ccc","ddd","eee");
        list.stream()
                .map((str) -> str.toUpperCase())
                .forEach(System.out::println);
        System.out.println("------------------------------");
        employees.stream()
                .map(Employee::getName)
                .forEach(System.out::println);
        System.out.println("-----------------------------");
        Stream<Stream<Character>> stream = list.stream()
                .map(TestStreamAPI2::filterCharacter);
        stream.forEach((sm) -> sm.forEach(System.out::println) );
        System.out.println("---------------------------");
        Stream<Character> sm = list.stream()
                .flatMap(TestStreamAPI2::filterCharacter);
        sm.forEach(System.out::println);
    }

    public static Stream<Character> filterCharacter(String str){
        List<Character> list = new ArrayList<>();
        for(Character ch :str.toCharArray()){
            list.add(ch);
        }
        return list.stream();
    }


    /** 排序
     *  sorted() ---- 自然排序(Comparable)
     *  sorted(Comparator com) ---- 定制排序
     */
    @Test
    public void test7(){
        List<String> list = Arrays.asList("ccc","aaa","bbb","ddd","eee");
        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 -e1.getAge().compareTo(e2.getAge());
                    }
                }).forEach(System.out::println);
    }

}
TestStreamAPI2

 3)终止操作

  • 查找与匹配
  1. allMatch --- 检查是否匹配所有元素
  2. anyMatch --- 检查是否至少匹配一个元素
  3. noneMatch --- 检查时候没有匹配所有元素
  4. findFirst ---- 返回第一个元素
  5. findAny ---- 返回当前流中的任意元素
  6. count ---- 返回流中元素的总个数
  7. max ---- 返回流中最大值
  8. min ---- 返回流中的最小值
  • 规约
  1. reduce(T identity,BinaryOperator) / reduce(BinaryOperator) ---- 可以将流中元素反复结合起来,得到一个值。
  • 收集
  1. collection ---- 将流转换为其他形式,接受一个 Collection 接口的实现,用于给 Stream 中元素做汇总的方法

测试代码如下:

package com.xq.stream;

import com.xq.design.model.Employee;
import com.xq.design.model.Employee.Status;
import org.junit.jupiter.api.Test;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 终止操作
 */
public class TestStreamAPI3 {
    List<Employee> employees = Arrays.asList(
            new Employee("张三",18,9999.99, Status.FREE),
            new Employee("李四",58,8888.88, Status.BUSY),
            new Employee("王五",26,5555.55, Status.VOCATION),
            new Employee("赵六",36,6666.66, Status.FREE),
            new Employee("田七",12,3333.33, Status.BUSY),
            new Employee("田七",12,3333.33, Status.BUSY)
    );
    /**
     * 查找与匹配
     * allMatch --- 检查是否匹配所有元素
     * anyMatch --- 检查是否至少匹配一个元素
     * noneMatch --- 检查时候没有匹配所有元素
     * findFirst ---- 返回第一个元素
     * findAny ----  返回当前流中的任意元素
     * count ---- 返回流中元素的总个数
     * max ---- 返回流中最大值
     * min ---- 返回流中的最小值
     */
    @Test
    public void test1(){
        Boolean b1 = employees.stream()
                .allMatch((e) -> e.getStatus().equals((Status.BUSY)));
        System.out.println(b1);

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

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

        Optional<Employee> op = employees.stream()
                .sorted((e1,e2) -> -Double.compare(e1.getSalary(),e2.getSalary()))
                .findFirst();
        System.out.println(op.get());
        Optional<Employee> op2 = employees.parallelStream()
                .filter((e) -> e.getStatus().equals(Status.FREE))
                .findAny();
        System.out.println(op2.get());
    }
    @Test
    public void test2(){
        Long count = employees.stream()
                .count();
        System.out.println(count);

        Optional<Employee> op1 = employees.stream()
                .max((e1,e2) -> Double.compare(e1.getSalary(),e2.getSalary()));
        System.out.println(op1.get());

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

    /**
     * 规约
     * reduce(T identity,BinaryOperator) / reduce(BinaryOperator) ---- 可以将流中元素反复结合起来,得到一个值。
     */
    @Test
    public void test3(){
        List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);

        Integer sun = list.stream()
                .reduce(0,(x,y) -> x+y);
        System.out.println(sun);
        System.out.println("----------------------");

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

    /**
     * 收集
     * collection ---- 将流转换为其他形式,接受一个 Collection 接口的实现,用于给 Stream 中元素做汇总的方法。
     */
    @Test
    public void test4(){
        List<String> list = employees.stream()
                .map(Employee::getName)
                .collect(Collectors.toList());
        list.forEach(System.out::println);
        System.out.println("---------------------");

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

        HashSet<String> hashSet = employees.stream()
                .map(Employee::getName)
                .collect(Collectors.toCollection(HashSet::new));
        hashSet.forEach(System.out::println);
    }
    @Test
    public void test5(){
        //总数
        Long count =employees.stream()
                .collect(Collectors.counting());
        System.out.println(count);

        //平均值
        Double ave = employees.stream()
                .collect(Collectors.averagingDouble((e) -> e.getSalary()));
        System.out.println(ave);
        //总和
        Double sum = employees.stream()
                .collect(Collectors.summingDouble(Employee::getSalary));
        System.out.println(sum);
        //最大工资的员工
        Optional<Employee> max = employees.stream()
                .collect(Collectors.maxBy((e1,e2) -> Double.compare(e1.getSalary(),e2.getSalary())));
        System.out.println(max.get());
        //最小工资
        Optional<Double> min = employees.stream()
                .map(Employee::getSalary)
                .collect(Collectors.minBy(Double::compare));
        System.out.println(min.get());
    }
    @Test
    public void test6(){
        //按照状态分组
        Map<Status,List<Employee>> map = employees.stream()
                .collect(Collectors.groupingBy(Employee::getStatus));
        System.out.println(map);
    }
    @Test
    public void test7(){
        //多级分组
        Map<Status,Map<String,List<Employee>>> map = employees.stream()
                .collect(Collectors.groupingBy(Employee::getStatus,Collectors.groupingBy((e) -> {
                    if(((Employee)e).getAge() <= 35){
                        return "二逼青年";
                    } else if(((Employee)e).getAge() <= 50){
                        return "中年";
                    } else {
                        return "老年";
                    }
                })));
        System.out.println(map);
    }
    @Test
    public void test8(){
        //分区
        Map<Boolean,List<Employee>> map = employees.stream()
                .collect(Collectors.partitioningBy((e) -> e.getSalary() > 8000));
        System.out.println(map);
    }
    @Test
    public void test9(){
        DoubleSummaryStatistics dss = employees.stream()
                .collect(Collectors.summarizingDouble(Employee::getSalary));
        System.out.println(dss.getSum());
        System.out.println(dss.getAverage());
        System.out.println(dss.getMax());
    }
    @Test
    public void test10(){
        String str = employees.stream()
                .map(Employee::getName)
                .collect(Collectors.joining(",","==","=="));
        System.out.println(str);
    }
}
TestStreamAPI3

 

posted @ 2020-02-16 02:43  l-coil  阅读(290)  评论(0编辑  收藏  举报