Stream流

Stream流

概述:

Stream流式思想类似于工厂车间的生产流水线,Stream流不是一种数据结构,不保存数据,而是对数据进行加工处理

为什么使用Stream流:

集合操作数据弊端很明显,每次都要循环遍历,还要创建新集合,很麻烦。

集合弊端:

List<String> list = new ArrayList<>();
        Collections.addAll(list, "张无忌", "周芷若", "李逍遥", "张三丰", "张三");
        /**
         * 1、拿到所有姓张的,2.拿到名字长度为三个字的,3.打印
         */
        List<String> nameList = new ArrayList<>();
        for (String name : list) {
            if (name.startsWith("张")) {
                nameList.add(name);
            }
        }
        List<String> threeList = new ArrayList<>();
        for (String name : nameList) {
            if (name.trim().length() == 3){
                threeList.add(name);
            }
        }
        threeList.forEach(s -> {
            System.out.println(s);
        });

Stream流操作:

        List<String> list = new ArrayList<>();
        Collections.addAll(list, "张无忌", "周芷若", "李逍遥", "张三丰", "张三");
        /**
         * 1、拿到所有姓张的,2.拿到名字长度为三个字的,3.打印
         */
        list.stream().filter(s -> {
            return s.startsWith("张");
        }).filter(s -> {
            return s.length()==3;
        }).forEach(s -> {
            System.out.println(s);
        });
获取Stream流的两种方式
  1. 通过Collection接口中的默认方法Stream stream()
  2. 通过Stream接口中的静态of方法
        /**
         * 方式一、根据Collection获取流
         *      default Stream<E> stream()
         *  因为是 default修饰 所以只要实现Collection接口的类都可使用
         */
        List<String> list = new ArrayList<>();
        Stream<String> stream = list.stream();

        Set<String> set = new HashSet<>();
        set.stream();

        Map<String, Object> map = new HashMap<>();
        Stream<Map.Entry<String, Object>> stream1 = map.entrySet().stream();
        Stream<Object> stream2 = map.values().stream();
        Stream<String> stream3 = map.keySet().stream();

        /**
         * 方式二、Stream中的静态方法of获取流
         * static<T> Stream<T> of(T... values)
         * 可变参,本质就是数组
         */
        Stream<String> stream4 = Stream.of("aa", "bb", "cc");

        String[] strs = {"aa", "bb", "cc"};
        Stream<String> stream5 = Stream.of(strs);
        /**
         *  基本数据类型的数据行不行??
         *     不行!!!!! stream会将整个数组看做一个元素进行操作
         */
        int[] arr = {11,22,33};
        Stream<int[]> stream6 = Stream.of(arr);  //不行
Stream流注意事项
  1. Stream流只能操作一次
  2. Stream调用非终结方法返回的是新的流
  3. Stream流最后不调用终结方法,中间的操作不会执行.
Stream流常用方法
方法名方法作用返回值类型方法种类
count统计个数long终结
forEach逐一处理void终结
filter过滤Stream函数拼接(非终结)
limit取用前几个Stream函数拼接
skip跳过前几个Stream函数拼接
map映射Stream函数拼接
concat组合Stream函数拼接

**终结:**返回类型不是Stream

**非终结:**返回类型是Stream

forEach方法 逐一处理
 List<String> list = new ArrayList<>();
        Collections.addAll(list, "张无忌", "周芷若", "李逍遥", "张三丰", "张三");

        list.stream().forEach(s->{
            System.out.println(s);
        });
        /**
         * 换成 方法引用写法
         */
        list.stream().forEach(System.out::println);
count方法 统计个数
List<String> list = new ArrayList<>();
        Collections.addAll(list, "张无忌", "周芷若", "李逍遥", "张三丰", "张三");

        System.out.println(list.stream().count());
filter方法 过滤
List<String> list = new ArrayList<>();
        Collections.addAll(list, "张无忌", "周芷若", "李逍遥", "张三丰", "张三");
        System.out.println(list.stream().filter(s -> {
            return s.startsWith("张");
        }).count());
limit方法 取前几个
 List<String> list = new ArrayList<>();
        Collections.addAll(list, "张无忌", "周芷若", "李逍遥", "张三丰", "张三");
        /**
         * 取集合前几个,这里取前两个
         * "张无忌", "周芷若"
         */
        list.stream().limit(2).forEach(s->{
            System.out.println(s);
        });
skip方法 跳过前几个
 List<String> list = new ArrayList<>();
        Collections.addAll(list, "张无忌", "周芷若", "李逍遥", "张三丰", "张三");
        /**
         * 跳过前几个.
         * "李逍遥", "张三丰"
         */
        list.stream().filter(s -> {
            return s.length() == 3;
        }).skip(2).forEach(s -> {
            System.out.println(s);
        });
map方法 映射类型转
List<String> list = new ArrayList<>();
//        Collections.addAll(list, "张无忌", "周芷若", "李逍遥", "张三丰", "张三");
        Collections.addAll(list, "111", "222", "333", "44", "55");
        /**
         *  map 映射可以将一种类型的流转换成另一种类型的流
         */
        /*Stream<Integer> integerStream = list.stream().map(s -> {
            return Integer.parseInt(s);
        });*/
        list.stream().map(s -> {
            return Integer.parseInt(s);
        }).forEach(s->{
            System.out.println(s);
        });
sorted 方法 排序
  • Stream<T> sorted();           //默认排序升序
    Stream<T> sorted(Comparator<? super T> comparator);  //自定义比较器
    
  Stream<Integer> stream = Stream.of(11, 22, 44, 33, 66, 55);
        /**
         * 默认排序(升序)
         */
        stream.sorted().forEach(System.out::println);
        /**
         * 指定比较器(降序)
         */
        stream.sorted((o1, o2) -> {
            return o2 - o1;
        }).forEach(System.out::println);
distinct方法 去重
 Stream<Integer> stream = Stream.of(11, 22, 44, 33, 66, 55,11);
        stream.distinct().forEach(System.out::println);
       /**
         * 去重类 ,这个类需要重写 equals和hashCode方法
         */
        Stream<Person> stream = Stream.of(
                new Person("张三", 15),
                new Person("张三", 16),
                new Person("张三", 17),
                new Person("张三", 15)
        );
        stream.distinct().forEach(System.out::println);
match方法 匹配指定条件
  • boolean allMatch(Predicate<? super T> predicate);  //匹配所有元素,所有元素都满足返回true
    boolean anyMatch(Predicate<? super T> predicate);  //匹配某个元素,只要有一个元素满足返回true
    boolean noneMatch(Predicate<? super T> predicate); //匹配所有元素,所有元素都不满足返回true
    
 Stream<Integer> stream = Stream.of(11, 22, 44, 33, 66, 55,11);
        /**
         * allMatch 匹配所有元素,所有元素都满足返回true
         */
        boolean b = stream.allMatch(s -> {
            return s > 20;
        });
        System.out.println(b);

        /**
         * anyMatch 匹配某个元素,只要有一个元素满足返回true
         */
        boolean b = stream.anyMatch(s -> {
            return s > 20;
        });
        System.out.println(b);
        /**
         * noneMatch 匹配所有元素,所有元素都不满足返回true
         */
        boolean b = stream.noneMatch(s -> {
            return s > 20;
        });
        System.out.println(b);
fina方法 找第一个元素
  • Optional<T> findFirst();   //找第一个元素  Optional 意味着可能找到可能找不到
    Optional<T> findAny();     //找第一个元素   
    
 Stream<Integer> stream = Stream.of(11, 22, 44, 33, 66, 55,11);
        /**
         * Optional 意味着可能找到可能找不到
         */
        Optional<Integer> streamFirst = stream.findFirst();
        System.out.println(streamFirst.get());

        Optional<Integer> any = stream.findAny();
        System.out.println(any.get());
max和min方法 最大值和最小值获取
    Stream<Integer> stream = Stream.of(11, 22, 44, 33, 66, 55,11);
        /**
         * 取最大 反之取最小,
         */
        /*Optional<Integer> max = stream.max((o1, o2) -> {
            return o1 - o2;
        });*/
        //简化写法
        Optional<Integer> max = stream.max(Comparator.comparingInt(o -> o));
        System.out.println(max.get());

      Stream<Integer> stream = Stream.of(11, 22, 44, 33, 66, 55,11);
        /**
         * 取最小
         */
        Optional<Integer> min = stream.min((o1, o2) -> {
            return o1 - o2;
        });
        System.out.println(min.get());
reduce方法 归纳数据得到结果
        Stream<Integer> stream = Stream.of(1,2,3);
        /**
         * T reduce(T identity, BinaryOperator<T> accumulator);
         * T identity:默认值
         * BinaryOperator<T> accumulator:对数据处理的方式
         */

        //取和
        Integer reduce = stream.reduce(0, (x, y) -> {
            return x + y;
        });
        System.out.println(reduce); //6  0+1+2+3

        //取最大值
        Integer reduce = stream.reduce(0, (x, y) -> {
            return x > y ? x : y;
        });
        System.out.println(reduce); //3  // 0 : 1  1:2 2 : 3
map结合reduce使用
 Stream<Person> stream = Stream.of(
                new Person("张三", 1),
                new Person("张三", 2),
                new Person("张三", 3),
                new Person("张三", 4)
        );
        // 求年龄总和
        Integer reduce = stream.map(p -> {
            return p.getAge();
        }).reduce(0, (x, y) -> {
            return x + y;
        });
        System.out.println(reduce);

        // 求最大年龄
        Integer reduce = stream.map(p -> {
            return p.getAge();
        }).reduce(0, (x, y) -> {
            return Math.max(x,y);
        });
        System.out.println(reduce);


        Stream<String> stream1 = Stream.of("a","b","c","a","a");
        //统计a出现的次数
        Integer a = stream1.map(s -> {
            if (s.equals("a")) {
                return 1;
            } else {
                return 0;
            }
        }).reduce(0, (x, y) -> {
            return Integer.sum(x, y);
        });
        System.out.println(a);
mapInt方法 将Integer类型Stream流转为IntStream
 // Integer占用内存比int多,在Stream流操作中会自动装箱拆箱
        Stream<Integer> stream = Stream.of(1, 2, 3);
        // IntStream 内部操作int类型数据,减少内存,减少自动装箱拆箱
        IntStream intStream = stream.mapToInt(s -> {
            return s.intValue();
        });
        intStream.forEach(System.out::println);
concat方法 合并两个流为一个流
  • static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b)
    
        Stream<Integer> integerStream = Stream.of(1, 2, 3);
        Stream<String> stringStream = Stream.of("1", "2", "3");
        Stream<? extends Serializable> stream = Stream.concat(integerStream, stringStream);
        stream.forEach(System.out::println);
收集Stream流中的结果
收集为集合collect
 Stream<Integer> stream = Stream.of(1, 2, 3,2);
        //收集到list集合中
        List<Integer> list = stream.filter(s -> {
            return s > 1;
        }).collect(Collectors.toList());

        //收集到set中
        Set<Integer> set = stream.filter(s -> {
            return s > 1;
        }).collect(Collectors.toSet());

        //收集到指定集合中 set同样
        ArrayList<Integer> arrayList = stream.filter(s -> {
            return s > 1;
        }).collect(Collectors.toCollection(ArrayList::new));

        HashSet<Integer> hashSet = stream.filter(s -> {
            return s > 1;
        }).collect(Collectors.toCollection(HashSet::new));
收集数组toArray
Stream<String> stream = Stream.of("aa","bb","vv");
        //转成Object数组  操作元素不方便
        Object[] objects = stream.toArray();
        System.out.println(Arrays.toString(objects));

        //转成原有类型
        String[] strings = stream.toArray(String[]::new);
        System.out.println(Arrays.toString(strings));
对流中数据进行聚合计算
        Stream<Person> stream = Stream.of(
                new Person("张三", 2),
                new Person("李四", 5),
                new Person("王五", 3)
        );
        //求最大值
        Optional<Person> collect = stream.collect(Collectors.maxBy(((o1, o2) -> {
            return o1.getAge() - o2.getAge();
        })));
        System.out.println("最大值:"+collect.get());

        //求最小值
        Optional<Person> collect = stream.collect(Collectors.minBy(((o1, o2) -> {
            return o1.getAge() - o2.getAge();
        })));
        System.out.println("最小值:"+collect.get());

        //求和
        Integer collect = stream.collect(Collectors.summingInt(s -> s.getAge()));
        System.out.println("总和:"+collect);

        //求平均值
        Double collect = stream.collect(Collectors.averagingInt(s -> s.getAge()));
        System.out.println("平均值:"+collect);

        //统计数量
        Long collect = stream.collect(Collectors.counting());
        System.out.println("数量:"+collect);
对流中数据进行分组(按条件分组)
 Stream<Person> stream = Stream.of(
                new Person("张三", 18),
                new Person("李四", 5),
                new Person("赵六", 5),
                new Person("王五", 20)
        );
        //根据age分组
        Map<Integer, List<Person>> map = stream.collect(Collectors.groupingBy(s -> s.getAge()));
        map.forEach((k,v)->{
            System.out.println("键:"+k+":::值:"+v);
        });

        //根据age分成年和未成年
        Map<String, List<Person>> map = stream.collect(Collectors.groupingBy(s -> {
            if (s.getAge() >= 18) {
                return "成年";
            } else {
                return "未成年";
            }
        }));
        map.forEach((k,v)->{
            System.out.println("键:"+k+":::值:"+v);
        });
对流中数据进行多级分组
 Stream<Person> stream = Stream.of(
                new Person("张三", 20,65),
                new Person("李四", 5,65),
                new Person("赵六", 5,88),
                new Person("王五", 20,88)
        );

        //先根据 age分组,在根据score分组
        Map<Integer, Map<Integer, List<Person>>> map = stream.collect(Collectors.groupingBy(s -> s.getAge(), Collectors.groupingBy(s -> s.getScore())));

        map.forEach((k,v)->{
            System.out.println(k);
            v.forEach((k2,v2)->{
                System.out.println("\t"+k2+"===="+v2);
            });
        });
        /*20
        65====[Person(name=张三, age=20, score=65)]
        88====[Person(name=王五, age=20, score=88)]
        5
        65====[Person(name=李四, age=5, score=65)]
        88====[Person(name=赵六, age=5, score=88)]*/
对流中数据进行分区
  • 满足条件是一个分区,不满足是另外一个分区
 //partitioningBy 满足条件true组 不满足 false组
        Map<Boolean, List<Person>> map = stream.collect(Collectors.partitioningBy(s -> {
            return s.getScore() > 60;
        }));
        map.forEach((k,v)->{
            System.out.println(k+"===="+v);
        });
      /*false====[Person(name=张三, age=20, score=55), Person(name=李四, age=5, score=58)]
        true====[Person(name=赵六, age=5, score=88), Person(name=王五, age=20, score=88)]*/
对流中数据进行拼接
  • Collectors.joining 会根据指定的连接符,将所有元素连接成一个字符串
      Stream<Person> stream = Stream.of(
                new Person("张三", 20,55),
                new Person("李四", 5,58),
                new Person("赵六", 5,88),
                new Person("王五", 20,88)
        );

        String collect = stream.map(s -> s.getName()).collect(Collectors.joining());
        System.out.println(collect);  //张三李四赵六王五

        String collect = stream.map(s -> s.getName()).collect(Collectors.joining("----"));
        System.out.println(collect); //张三----李四----赵六----王五

        String collect = stream.map(s -> s.getName()).collect(Collectors.joining("-","KK_","EE"));
        System.out.println(collect); //KK_张三-李四-赵六-王五EE
并行的Stream流
  • 串行Stream流 , 就是在一个线程上执行
 Stream.of(1,2,3).filter(s->{
            System.out.println(Thread.currentThread()+"==="+s);
            return s > 1;
        }).count();
       /* Thread[main,5,main]===1
          Thread[main,5,main]===2
          Thread[main,5,main]===3*/
  • 获取并行流的两种方式
 List<String> list = new ArrayList<>();
        //方式一: 直接获取并行的Stram流
        Stream<String> stringStream = list.parallelStream();
        //方式二: 将串行流转成并行流
        Stream<String> parallel = list.stream().parallel();
  • 并行流,不同的线程调用 效果
 Stream.of(1,2,3).parallel()
                .filter(s->{
            System.out.println(Thread.currentThread()+"==="+s);
            return s > 1;
        }).count();
       /* Thread[ForkJoinPool.commonPool-worker-2,5,main]===3
          Thread[main,5,main]===2
          Thread[ForkJoinPool.commonPool-worker-9,5,main]===1 */
并行Stream流线程安全问题
  • 线程不安全的情况
  List<Integer> list = new ArrayList<>();
       IntStream.rangeClosed(1,1000)
               .parallel()
               .forEach(s->{
                   list.add(s);
               });
        System.out.println("集合大小::"+list.size());  //950  946
  1. 解决方案一: synchronized
 List<Integer> list = new ArrayList<>();
        Object obj = new Object();
        IntStream.rangeClosed(1,1000)
                .parallel()
                .forEach(s->{
                    synchronized (obj){
                        list.add(s);
                    }
                });
        System.out.println("集合大小::"+list.size());  //集合大小::1000
2. 解决方案二: 使用线程安全的集合
//使用线程安全的集合一
Vector vector = new Vector();
IntStream.rangeClosed(1,1000)
        .parallel()
        .forEach(s->{
            vector.add(s);
        });
System.out.println("集合大小::"+vector.size());  //集合大小::1000

//使用线程安全的集合二
     List<Integer> list = new ArrayList<>();  
     List<Integer> synchronizedList = Collections.synchronizedList(list);
     IntStream.rangeClosed(1,1000)
                .parallel()
                .forEach(s->{
                    synchronizedList.add(s);
                });
     System.out.println("集合大小::"+synchronizedList.size());  //集合大小::1000

​ 3.解决方案三: 使用stream流的收集collect(线程安全)

    List<Integer> collect = IntStream.rangeClosed(1, 1000)
                .parallel()
                .boxed()  //先装箱
                .collect(Collectors.toList());
        System.out.println("集合大小::"+collect.size());  //集合大小::1000
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值