Stream流 Java8新特性

1. Stream流的创建

/**
 * 流是什么?
 *      是数据渠道, 用于操作数据源(集合, 数组等) 所生成的元素序列.
 *      集合讲的是数据, 流讲的是计算
 *
 * 注意:
 *      1. Stream 自己不会存储元素
 *      2. Stream 不会改变源对象. 相反, 他们会返回一个持有结果的新Stream.
 *      3. Stream 操作是延迟执行的. 这意味着他们会等需要结果的时候才执行.
 *
 * 操作:
 *      1. 创建Stream : 一个数据源(集合, 数组) , 获取一个流
 *      2. 中间操作 : 一个中间操作链对数据源的数据进行处理
 *      3. 终止操作 : 一个终止操作, 执行中间操作链, 并产生结果
 *
 * 获取流:
 *      1. Collection系列集合提供的stream() 或 parallelStream()
 *          List<String> list = new ArrayList<>();
 *          Stream<String></> stream = list.stream();
 *
 *      2. 通过Arrays 中的静态方法 stream() 获取数组流
 *          Employee[] employees = new Employee[10];
 *          Stream<Employee> stream = Arrays.stream(employees);
 *
 *      3. 通过Stream类中静态方法 of()
 *          Stream<String> stream = Stream.of("aa","bb","cc");
 *
 *      4. 创建无限流
 *          1. 迭代   Stream<Integer> stream = Stream.iterator(0,x -> x + 2);
 *          2. 生成   Stream<Double> stream = Stream.generate(() -> Math.random());
 */

public class StreamTest {

    @Test
    public void test(){

        Stream<Integer> stream = Stream.iterate(0,x -> x + 2);
        stream.limit(10).forEach(System.out::println);
    }

}

2. 流的中间操作

     2.1.  筛选和切片

/**
 * Stream流的中间操作:
 *  1. 筛选与切片
 *      filter : 接受lambda, 从流中排出某些元素.
 *      limit :  截断流, 使其元素不超过指定数量.
 *      skip(n) : 跳过元素, 返回一个扔掉了前n个元素的流. 若元素不足n个, 则返回一个空流.  与limit(n)互补.
 *      distinct : 筛选, 通过流所生成元素的hashCode() 和 equals() 去除重复元素.  对于自定义对象而言, 要重写这两个方法
 *
 *  注意:
 *      由结果可知, 执行过程中出现了迭代, 这是由Stream API产生 -- 内部迭代
 *      中间操作不会执行任何操作, 终止操作一次性执行全部内容, 即: 延迟加载(惰性求值)
 *      通过短路来提高效率, 找到合适的元素则不会向下执行 类似于 &&  ||
 */

public class StreamAPITest {

    List<Employee> employees = Arrays.asList(
            new Employee("张三",18,9000.00),
            new Employee("李四",48,6666.00),
            new Employee("王五",28,8080.00),
            new Employee("赵六",38,5900.00),
            new Employee("小张",30,3900.00),
            new Employee("老王",40,2900.00),
            new Employee("小李",19,1900.00),
            new Employee("老李",39,8900.00),
            new Employee("老李",39,8900.00),
            new Employee("老李",39,8900.00)
    );

    // 内部迭代: 由Stream API完成
    @Test
    public void test(){
        //employees.stream().filter( employee -> {
                        //System.out.println("Stream API Filter 操作");
                        //return employee.getAge() > 30;
                    //})
                //.forEach(System.out::println);


        employees.stream().filter( employee -> employee.getAge() > 30)
                 //.limit(3)
                 .skip(1)
                 .distinct()
                 .forEach(System.out::println);
    }

}

 

      2.2.  流的映射

/**
 *  映射
 *      map : 接受Lambda , 将元素转换成其他形式或提取信息. 接收一个函数作为参数,
 *            该函数会被应用到每个元素上, 并将其映射成一个新元素.
 *
 *      flatMap : 接收一个函数作为参数, 将流中每一个值都换成另一个流, 然后把所有流连成一个流.
 *
 *  注意:
 *      map 方法类似于 List 集合中 add()
 *          List<String> list = new ArrayList<>();  list.add("aaa"); list.add("bbb");
 *          List list2 = new ArrayList<>();
 *          list2.add(111);
 *          list2.add(list);   // [111,[aaa,bbb]]
 *
 *      flatMap 类似于 list 集合中 addAll()方法
 *          list2.addAll(list);   // [111,aaa,bbb]
 */

public class StreamAPITest2 {

    List<Employee> employees = Arrays.asList(
            new Employee("张三",18,9000.00),
            new Employee("李四",48,6666.00),
            new Employee("王五",28,8080.00),
            new Employee("赵六",38,5900.00),
            new Employee("小张",30,3900.00),
            new Employee("老王",40,2900.00),
            new Employee("小李",19,1900.00),
            new Employee("老李",39,8900.00),
            new Employee("老李",39,8900.00),
            new Employee("老李",39,8900.00)
    );

    @Test
    public void test(){
        List<String> list = Arrays.asList("aaa","bbb","ccc","ddd","eee");
        list.stream().map(str -> str.toUpperCase()).forEach( str -> System.out.print(str + " "));
        //employees.stream().map( employee -> employee.getName()).forEach( str -> System.out.print(str + " "));
        System.out.println();
        System.out.println("-------------------------------");

        // 注意返回结果类型 类似于{{a,a,a},{b,b,b},{c,c,c},{d,d,d}}
        Stream<Stream<Character>> streamStream = list.stream().map(StreamAPITest2::filterCharacter);
        streamStream.forEach(stream -> {stream.forEach(s -> System.out.print(s + " "));});

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

        // 使用flatMap方法 得到结果类型 类似于 {a,a,a,b,b,b,c,c,c}
        Stream<Character> characterStream = list.stream().flatMap(StreamAPITest2::filterCharacter);
        characterStream.forEach(s -> System.out.print(s + " "));

    }

    // 将字符串每个字符存入list集合中
    public static Stream<Character> filterCharacter(String str){
        List<Character> list = new ArrayList<>();

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

        return list.stream();
    }

}

      2.3.  排序

/**
 * 排序:
 *    sorted() : 自然排序(Comparable)
 *
 *    sorted(Comparator comparator) : 定制排序
 *
 */
public class StreamAPITest3 {

    List<Employee> employees = Arrays.asList(
            new Employee("张三",18,9000.00),
            new Employee("李四",48,6666.00),
            new Employee("王五",28,8080.00),
            new Employee("赵六",38,5900.00),
            new Employee("小张",30,3900.00),
            new Employee("老王",40,2900.00),
            new Employee("小李",19,1900.00),
            new Employee("老李",39,8900.00)
    );

    @Test
    public void test(){

        List<String> list = Arrays.asList("ccc","aaa","ddd","bbb");
        // 自然排序
        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);

    }

}

3. 终端操作

/**
 * 终止操作:
 *
 *   查找与匹配
 *      allMatch : 检查是否匹配所有元素       所有都是
 *      anyMatch : 检查是否至少匹配一个元素   任意一个是
 *      noneMatch : 检查是否没有匹配所有元素  所有的都不是   跟allMatch相反
 *      findFirst : 返回第一个元素           返回 Optional<T>类型
 *      findAny : 返回当前流中任意元素        返回Optional<T> 类型
 *      count : 返回流中元素个数
 *      max : 返回流中最大值
 *      min : 返回流中最小值
 *
 */

public class StreamAPITest4 {

    List<Employee> employees = Arrays.asList(
            new Employee("张三",18,9000.00),
            new Employee("李四",48,6666.00),
            new Employee("王五",28,8080.00),
            new Employee("赵六",38,5900.00),
            new Employee("小张",30,13900.00),
            new Employee("老王",40,2900.00),
            new Employee("小李",19,1900.00),
            new Employee("老李",39,8900.00)
    );

    @Test
    public void test(){
        // 是否所有人的工资都大于1000元  true
        boolean b = employees.stream().allMatch(employee -> employee.getSalary() > 5000d);
        System.out.println("是否所有人的工资都超过1000元: " + b);     // false

        boolean b1 = employees.stream().anyMatch(employee -> employee.getSalary() > 10000d);
        System.out.println("是否有人的工资超哥10000元: " + b1);       // true

        boolean b2 = employees.stream().noneMatch(employee -> employee.getSalary() > 14000d);
        System.out.println("是否所有人的工资都不超过14000元: " + b2);  // true

        boolean b3 = employees.stream().noneMatch(employee -> employee.getSalary() < 1000d);
        System.out.println("是否所有人的工资都大于1000元: " + b3);     // true
        
        // 按工资排序, 再去第一个元素
        Optional<Employee> first = employees.stream().sorted(Comparator.comparingDouble(Employee::getSalary)).findFirst();
        System.out.println(first.get());

        // 获取工资高于5000的, 随意取出一个
        Optional<Employee> any = employees.stream().filter(e -> e.getSalary() > 5000d).findAny();
        System.out.println(any.get());

        // 获取元素个数
        long count = employees.stream().count();
        System.out.println("流中元素有: " + count);

        // 获取最大值的元素, 指定方式 工资最大的
        Optional<Employee> max = employees.stream().max(Comparator.comparingDouble(Employee::getSalary));
        System.out.println(max.get());

        // 获取最小值得元素, 指定方式 年龄最小的
        Optional<Integer> min = employees.stream().map(Employee::getAge).min(Integer::compare);
        System.out.println("年龄最小的是: " + min.get());
    }

}

4.  归约 收集 分组 分区

/**
 * 归约
 *    reduce(T identify,BinaryOperator)
 *    reduce(BinaryOperator)
 *    可以将流中元素反复结合起来, 得到一个值
 *
 * 收集
 *    collect : 将流转换为其他形式. 接收一个Collector接口的实现, 用于给Stream中元素做汇总的方法
 *              Collector接口中方法的实现决定了如何对流执行收集操作(如收集到 List, Set , Map),
 *              但是 Collectors 实用类提供了很多静态方法, 可以方便地创建常见收集器实例.
 *
 * 分组 / 多级分组
 *
 * 分区
 *
 * joining() 用法
 *
 * 注意:
 *    map 和 reduce的连接通常称为map - reduce 模式, 因Google用它来进行网络搜索而出名.
 *
 */

public class StreamAPITest5 {

    List<Employee> employees = Arrays.asList(
            new Employee("张三",18,9000.00),
            new Employee("李四",48,6666.00),
            new Employee("王五",28,8080.00),
            new Employee("赵六",38,5900.00),
            new Employee("小张",30,13900.00),
            new Employee("老王",40,2900.00),
            new Employee("小李",19,1900.00),
            new Employee("老李",39,8900.00),
            new Employee("老李",39,8900.00)
    );

    @Test
    public void test(){
        List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);

        // 第一次将 0 赋值给x , 1 赋值给 y , 求和 赋值给x , 在取下一个元素赋值给 y, 以此循环计算
        Integer sum = list.stream().reduce(0, (x, y) -> x + y);
        System.out.println(sum);

        // 求所有员工的工资总和
        Double sumSalary = employees.stream().map(Employee::getSalary).reduce(0.0, (x, y) -> x + y);
        System.out.println(sumSalary);  // 57246.0

        // 此种方法无起始值, 有可能为空, 所有用 Optional类型接收
        Optional<Double> reduce = employees.stream().map(Employee::getSalary).reduce(Double::sum);
        System.out.println(reduce.get());   // 57246.0

        // collect收集器  Stream --> List
        List<String> collect = employees.stream().map(Employee::getName).collect(Collectors.toList());
        System.out.println(collect);
        // Stream --> Set  可去重
        Set<String> collect1 = employees.stream().map(Employee::getName).collect(Collectors.toSet());
        System.out.println(collect1);

        // Stream --> 其他特殊集合
        HashSet<String> collect2 = employees.stream().map(Employee::getName).collect(Collectors.toCollection(HashSet::new));
        System.out.println(collect2);

        // 总数
        Long collect3 = employees.stream().collect(Collectors.counting());

        // 平均值
        Double collect4 = employees.stream().collect(Collectors.averagingDouble(Employee::getSalary));

        // 总和
        DoubleSummaryStatistics collect5 = employees.stream().collect(Collectors.summarizingDouble(Employee::getSalary));

        // 最大值
        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());


        // 分组 根据姓名分组 获得 key - value
        Map<String,List<Employee>> map = employees.stream().collect(Collectors.groupingBy(Employee::getName));

        // 多级分组
        Map<String,Map<String,List<Employee>>> map1 = employees.stream().collect(Collectors.groupingBy(Employee::getName,Collectors.groupingBy((e) -> {
            if(((Employee)e).getAge() <= 35){
                return "青年";
            }else{
                return "中年";
            }
        })));


        // 分区 满足条件一个区域  不满足条件一个区域  一个false区, 一个true区
        Map<Boolean,List<Employee>> map3 = employees.stream().collect(Collectors.partitioningBy( e -> e.getSalary() > 8000));

        // 获取 总数, 平均值, 最大值 另一种方式
        DoubleSummaryStatistics dss = employees.stream().collect(Collectors.summarizingDouble(Employee::getSalary));
        System.out.println(dss.getAverage());
        System.out.println(dss.getCount());
        System.out.println(dss.getSum());
        System.out.println(dss.getMax());
        System.out.println(dss.getMin());


        // 获取所有姓名  joining(",","==","===") 还可以加上首尾
        String str = employees.stream().map(Employee::getName).collect(Collectors.joining(","));
        System.out.println(str);
    }

}

 

 

 

 

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值