Stream API

Stream 图解
什么是Stream?
是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。
“集合讲的是数据,流讲的是计算!”
注意:
①Stream 自己不会存储元素。
②Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。
③Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。
Stream 的操作三个步骤
⚫ 创建 Stream
一个数据源(如:集合、数组),获取一个流
⚫ 中间操作
一个中间操作链,对数据源的数据进行处理
⚫ 终止操作(终端操作)
一个终止操作,执行中间操作链,并产生结果
Stream 操作步骤图解

/**
 * 一、Stream 的操作三个步骤
 * 1.创建 Stream
 * 一个数据源(如:集合、数组),获取一个流
 * 2.中间操作
 * 一个中间操作链,对数据源的数据进行处理
 * 3.终止操作(终端操作)
 * 一个终止操作,执行中间操作链,并产生结果
 */
public class StreamApiTest {
    //创建Stream
    @Test
    public void test1(){
        //1.可以通过Collection系列集合提供的stream() 或 parallelStream
        List<String> list = new ArrayList<>();
        Stream<String> stream1 = list.stream();

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

        //3.通过Stream类中的静态方法of()
        Stream<String> stream3 = Stream.of("Hello","world","java");

        //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);

    }
    /**
     * Stream的中间操作:
     * 多个中间操作可以连接起来形成一个流水线,除非流水
     * 线上触发终止操作,否则中间操作不会执行任何的处理!
     * 而在终止操作时一次性全部处理,称为“惰性求值”。
     *
     */

    /**
     * 筛选与切片
     * filter --- 接收Lambda,从流中排除某些元素
     * limit --- 截断流,使其元素不超过给定数量
     * skip(n) --- 跳过元素,返回一个扔掉了前n个元素的流。若流中元素不足n个,则返回一个空流,与limit(n)互补。
     * distinct -- 筛选,通过流所生成元素的hashCode() 和 equals() 去除重复元素
     */
    List<Employee> employeeList = Arrays.asList(
            new Employee("张三",45,999.99),
            new Employee("李四",38,666.66),
            new Employee("赵六",25,333.33),
            new Employee("王五",32,555.55),
            new Employee("王五",32,555.55),
            new Employee("田七",18,111.11)
    );
    //内部迭代:迭代操作由Stream API完成
    @Test
    public void test2(){
        //中间操作:不会执行任何操作
        Stream<Employee> stream = employeeList.stream()
                                    .filter(e -> {
                                        System.out.println("Stream API 的中间操作");
                                        return e.getAge()>35;
                                    });
        //终止操作:一次性执行全部内容,即“惰性求值”
        stream.forEach(System.out::println);
    }
    //外部迭代
    @Test
    public void test3(){
        Iterator<Employee> it = employeeList.iterator();
        while (it.hasNext()){
            System.out.println(it.next());
        }
    }
    //短路:limit找到符合条件的数量后后续的迭代操作不再进行,即短路,一定程度上提高了效率
    @Test
    public void test4(){
        employeeList.stream()
                .filter(e -> {
                    System.out.println("短路!");
                    return e.getSalary()>400;
                })
                .limit(2)
                .forEach(System.out::println);

    }
    /**
     * 映射
     * map -- 接收 Lambda,将袁术转换成其他啊形式或提取信息。接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
     * flatMap -- 接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流。
     */
    @Test
    public void test5(){
        List<String> list = Arrays.asList("aaa","bbb","ccc","ddd","eee");
        list.stream()
                .map((str) -> str.toUpperCase())
                .forEach(System.out::println);
        System.out.println("-----------------");

        employeeList.stream()
                .map(Employee::getName)
                .forEach(System.out::println);
        System.out.println("---------------");
        Stream<Stream<Character>> stream = list.stream()
                .map(StreamApiTest::filterCharacter);//{{a,a,a}{b,b,b}}
        stream.forEach(sm -> {
            sm.forEach(System.out::println);
        });
        System.out.println("--------------");
        Stream<Character> sm = list.stream()
                .flatMap(StreamApiTest::filterCharacter);//{a,a,a,b,b,b}
    }
    public static Stream<Character> filterCharacter(String str){
        List<Character> list = new ArrayList<>();
        for (Character ch : str.toCharArray()) {
            list.add(ch);
        }
        return list.stream();
    }
    //中间操作中的map和flatmap类似于集合中add()和addAll()方法
    @Test
    public void test6(){
        List<String> list = Arrays.asList("aaa","bbb","ccc");
        List list2 = new ArrayList();
        list2.add(11);
        list2.add(22);
//        list2.add(list);
//        System.out.println(list2);
        //[11, 22, [aaa, bbb, ccc]]
        list2.addAll(list);
        System.out.println(list2);
        //[11, 22, aaa, bbb, ccc]
    }
    /**
     * 排序
     * sorted() -- 自然排序(Comparable)
     * sorted(Comparator com) -- 定制排序(Comparator)
     */
    @Test
    public void test7(){
        List<String> list = Arrays.asList("aaa","bbb","ccc");
        list.stream()
                .sorted()
                .forEach(System.out::println);
        // aaa  bbb  ccc
        System.out.println("--------------");
        employeeList.stream()
                .sorted((e1,e2) -> e1.getName().compareTo(e2.getName()))
                .forEach(System.out::println);
//        Employee{name='张三', age=45, salary=999.99}
//        Employee{name='李四', age=38, salary=666.66}
//        Employee{name='王五', age=32, salary=555.55}
//        Employee{name='田七', age=18, salary=111.11}
//        Employee{name='赵六', age=25, salary=333.33}
    }
    /**
     * 终止操作
     *
     * allMatch --检查是否匹配所有元素
     * anyMatch --检查是否至少匹配一个元素
     * noneMatch --检查是否没有匹配所有元素
     * findFirst --返回第一个元素
     * findAny -- 返回当前流中的任意元素
     * count -- 返回流中元素的总个数
     * max -- 返回流中最大值
     * min -- 返回流中最小值
     */
    List<Employee> streamEmployeeList = Arrays.asList(
            new Employee("张三",45,999.99, Employee.Status.BUSY),
            new Employee("李四",38,666.66,Employee.Status.FREE),
            new Employee("赵六",25,333.33, Employee.Status.VOCATION),
            new Employee("王五",32,555.55, Employee.Status.BUSY),
            new Employee("田七",18,111.11, Employee.Status.VOCATION)
    );
    @Test
    public void test8(){
        boolean b1 = streamEmployeeList.stream()
                .allMatch(e -> e.getStatus().equals(Employee.Status.BUSY));
        //false
        boolean b2 = streamEmployeeList.stream()
                .anyMatch(e -> e.getStatus().equals(Employee.Status.BUSY));
                //true
        boolean b3 = streamEmployeeList.stream()
                .noneMatch(e -> e.getStatus().equals(Employee.Status.BUSY));
                //false
        //将返回值放到容器Optional中,是为了防止.findFirst()方法空指针异常,
        Optional<Employee> op = streamEmployeeList.stream()
                .sorted((e1,e2) -> Double.compare(e1.getSalary(),e2.getSalary()))
                .findFirst();
        System.out.println(op.get());
        Optional<Employee> op2 = streamEmployeeList.stream()
                .filter(e -> e.getStatus().equals(Employee.Status.FREE))
                .findAny();
        System.out.println(op2.get());
    }
    @Test
    public void test9(){
        Long count = streamEmployeeList.stream()
                        .count();
        System.out.println(count);//5
        Optional<Employee> op = streamEmployeeList.stream()
                .max((e1,e2) -> Double.compare(e1.getSalary(),e2.getSalary()));
        System.out.println(op.get());
        //Employee{name='张三', age=45, salary=999.99}
        Optional<Double> op2 = streamEmployeeList.stream()
                .map(Employee::getSalary)
                .min(Double::compare);
        System.out.println(op2.get());
        //111.11
    }
    /**
     * 归约
     * reduce(T iden, BinaryOperator b)  /  reduce(BinaryOperator b)
     * 可以将流中元素反复结合起来,得到一个值。
     */
    @Test
    public void test10(){
        List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
        Integer sum = list.stream()
                .reduce(0,(x,y) -> x+y);
        //初始值0赋给x,流中1赋给y
        System.out.println(sum);//55
        //没有起始值,可能为空,返回optional
        Optional<Double> op = employeeList.stream()
                .map(Employee::getSalary)
                .reduce(Double::sum);
        //备注:map 和 reduce 的连接通常称为map-reduce 模式,因 Google 用它
        //来进行网络搜索而出名。
        System.out.println(op.get());
    }
    /**
     * 收集
     * collect--- 将流转换为其他形式。接收一个 Collector接口的实现,用于给Stream中元素做汇总的方法
     * Collector 接口中方法的实现决定了如何对流执行收集操作(如收
     * 集到 List、Set、Map)。但是 Collectors 实用类提供了很多静态
     * 方法,可以方便地创建常见收集器实例
     */
    @Test
    public void test11(){
        List<String> list = employeeList.stream()
                .map(Employee::getName)
                .collect(Collectors.toList());
        list.forEach(System.out::println);
        System.out.println("----------------");
        Set<String> set = employeeList.stream()
                .map(Employee::getName)
                .collect(Collectors.toSet());
        set.forEach(System.out::println);
        System.out.println("----------------");
        //还可以指定集合
        HashSet<String> hs = employeeList.stream()
                .map(Employee::getName)
                .collect(Collectors.toCollection(HashSet::new));
        hs.forEach(System.out::println);
    }
    @Test
    public void test12(){
        //总数
        Long count = employeeList.stream()
                .collect(Collectors.counting());
        System.out.println(count);
        System.out.println("----------------");
        //平均值
        Double avg = employeeList.stream()
                .collect(Collectors.averagingDouble(Employee::getSalary));
        System.out.println(avg);
        System.out.println("-----------------");
        //总和
        Double sum = employeeList.stream()
                .collect(Collectors.summingDouble(Employee::getSalary));
        System.out.println(sum);
        //最大值
        Optional<Employee> max = employeeList.stream()
                .collect(Collectors.maxBy((e1,e2)->Double.compare(e1.getSalary(),e2.getSalary())));
        System.out.println(max.get());
        //最小值
        Optional<Double> min = employeeList.stream()
                .map(Employee::getSalary)
                .collect(Collectors.minBy(Double::compare));
        System.out.println(max.get());
    }
    //分组
    @Test
    public void test13(){
        Map<Employee.Status,List<Employee>> map = streamEmployeeList.stream()
                .collect(Collectors.groupingBy(Employee::getStatus));
        System.out.println(map);
    }
    //多级分组
    @Test
    public void test14(){
        Map<Employee.Status,Map<String,List<Employee>>> map = streamEmployeeList.stream()
                .collect(Collectors.groupingBy(Employee::getStatus,Collectors.groupingBy((e)->{
                    if (((Employee) e).getAge() <= 35){
                        return "青年";
                    }else if (((Employee) e).getAge() <= 50) {
                        return "中年";
                    } else {
                        return "老年";
                    }
                })));
    }
    //分片/分区--满足条件的一个区,不满足条件的一个区
    @Test
    public void test15(){
        Map<Boolean,List<Employee>> map = employeeList.stream()
                .collect(Collectors.partitioningBy((e) -> e.getSalary()>500));
        System.out.println(map);
        //{false=[Employee{name='赵六', age=25, salary=333.33}, Employee{name='田七', age=18, salary=111.11}],
        // true=[Employee{name='张三', age=45, salary=999.99}, Employee{name='李四', age=38, salary=666.66}, Employee{name='王五', age=32, salary=555.55}, Employee{name='王五', age=32, salary=555.55}]}
    }
    @Test
    public void test16(){
        DoubleSummaryStatistics dss = employeeList.stream()
                .collect(Collectors.summarizingDouble(Employee::getSalary));
        System.out.println(dss.getMax());
        System.out.println(dss.getAverage());
        System.out.println(dss.getSum());
    }
    //拼接字符串
    @Test
    public void test17(){
        String str = employeeList.stream()
                .map(Employee::getName)
                .collect(Collectors.joining(","));
        System.out.println(str);
        //张三,李四,赵六,王五,王五,田七
    }
    /**
     * 练习1
     * 给定一个数字列表,返回一个由每个数的平方构成的列表
     * 给定[1,2,3,4,5],返回[1,4,9,16,25]
     */
    @Test
    public void test18(){
        Integer[] nums = new Integer[] {1,2,3,4,5};
        Arrays.stream(nums)
                .map((x) -> x*x)
                .forEach(System.out::println);
    }
    /**
     * 练习2
     * 怎么用map 和 reduce 方法数一数流中有多少哥Employee呢?
     */
    @Test
    public void test19(){
        Optional<Integer> op = employeeList.stream()
                .map((e) -> 1)
                .reduce(Integer::sum);
        System.out.println(op.get());
        //6
    }

}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值