stream流操作

一,stream概述

stream流操作是jdk8的新增特性,配合lambda表达式,能够极大的简化对于集合的操作(每次都要循环遍历,创建新集合)。

stream流特性:
1,stream不会存储数据,而是按照特定规则对数据处理
2,stream不会改变数据源,通常会产生一个新的集合或值
3,stream流具有延迟执行特性,只有调用终端操作才会执行

二,stream的创建

1,使用java.util.stream.Stream()方法

        List<String> list=new ArrayList();
        Stream<String> stream = list.stream();

        Set<String> set=new HashSet<>();
        Stream<String> stream1 = set.stream();
        
        // map不是集合,可以通过获取其keySet或者value来创建流
        Map<String,String> map=new HashMap<>();
        Stream<String> stream2 = map.keySet().stream();
        Stream<String> stream3 = map.values().stream();

2,使用Stream中的静态方法of()

        Stream<String> aa = Stream.of("aa", "bb", "cc");
        aa.forEach(a-> System.out.println(a));

3,使用java.util.Arrays.stream(T[] array)方法用数组创建流

        int[] array={1,2,3,4};
        IntStream stream4 = Arrays.stream(array);

三,stream常见方法

1,stream方法的分类

终结方法:返回类型不是stream类型的方法,不支持链式调用,每个流只能调用一次终结方法,调用后产生新的集合或值。只有调用终结方法stream的中间操作才会执行
非终结方法:返回类型为stream类型的方法,支持链式调用

2,注意事项

2.1,一个stream只能操作一次

        Stream<String> stream5 = Stream.of("aa", "bb", "cc");
        stream5.count();
        stream5.count();
        // 会报错 Exception in thread "main" java.lang.IllegalStateException: stream has already been operated upon or closed

2.2,stream流返回的是新的流

2.3,只有调用终结方法stream的中间操作才会执行

3,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,"迪丽热巴","宋远桥","苏星河","老子","庄子","孙子");
        list.stream().count();

filter()方法:非终结方法,返回符合过滤条件的数据

        List<String> list=new ArrayList<>();
        Collections.addAll(list,"迪丽热巴","宋远桥","苏星河","老子","庄子","孙子");

      //获取名字长度为3的元素
      //宋远桥,苏星河
      list.stream().filter(a->
             a.length()==3
        ).forEach(System.out::println);

limit()方法,非终结方法,获取流中的前n个元素

        List<String> list=new ArrayList<>();
        Collections.addAll(list,"迪丽热巴","宋远桥","苏星河","老子","庄子","孙子");
        //迪丽热,巴宋远桥,苏星河
        list.stream().limit(3).forEach(System.out::println);

skip()方法,非终结方法,跳过流中前n个元素,截取之后的元素。若n大于集合的长度,则会获取长度为0的空流

        List<String> list=new ArrayList<>();
        Collections.addAll(list,"迪丽热巴","宋远桥","苏星河","老子","庄子","孙子");
        //老子,庄子,孙子
        list.stream().skip(3).forEach(System.out::println);

map(),非终结方法,将流中的元素映射到另一个流中

        //将流中的字符串转为Integer
        Stream<String> stringStream = Stream.of("1", "2", "3");
        stringStream.map(s -> Integer.valueOf(s)).forEach(System.out::println);

sorted()方法非终结方法,对流中的数据进行排序

//        1,sorted()根据元素的自然顺序排序
//          升序
           Stream.of(3, 7, 1, 8, 0, 9).sorted().forEach(System.out::println);
//        2,sorted(Comparator<? super T> comparator)根据比较器定义的规则排序
//          降序
           Stream.of(3, 7, 1, 8, 0, 9).sorted((i1,Ii2)->i2 - i1).forEach(System.out::println);    


distinct()非终极方法,去除流中的重复元素

         
         Stream.of(3, 1, 1, 3, 0, 2).distinct().forEach(System.out::println);

         //自定义对象的去重,要重写equals方法和hashCode方法
        Stream<Person> personStream = Stream.of(new Person("小明", "11"), new Person("小明", "11"), new Person("小红", "12"));
        personStream.distinct().forEach(System.out::println);

match()终结方法,
allMatch()匹配所有,所有元素都满足条件返回true,否则返回false
anyMatch()匹配某个元素,只要有一个元素满足条件返回true
noneMatch()匹配所有,所有元素都不满足条件返回ture

//        false,true,true
          Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 5);
//        System.out.println(integerStream.allMatch(i->i>3));
//        System.out.println(integerStream.anyMatch(i->i>3));
          System.out.println(integerStream.noneMatch(i->i>6));

find()方法
findFirst()找第一个元素
findAny()找第一个元素

        Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 5);
        System.out.println(integerStream.findAny().get());

max(),min()获取最大值,最小值

        Optional<Integer> max = integerStream.max((i1, i2) -> i1 - i2);
        System.out.println(max.get());

reduce()将所有的数据归纳得到一个数据

//        T reduce(T identity, BinaryOperator<T> accumulator);
//        identity:默认值
//        BinaryOperator<T>:对数据处理的方式
        Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 5);
        Integer reduce = integerStream.reduce(0, (a, b) -> a + b);
        System.out.println(reduce);


concat()将两个流合并成一个流,合并后不能在操作合并前的流

        Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 5);
        Stream<Integer> integerStream1 = Stream.of(5, 6, 7);
        Stream.concat(integerStream,integerStream1).forEach(System.out::println);

四,收集stream流中的结果

对流进行操作后,将结果保存到数组或集合中
stream提供方法collect()

        Stream<String> stream = Stream.of("a", "b");
        //将流中的结果收集到list中
        List<String> collect = stream.collect(Collectors.toList());
        //将流中的结果收集到set中
        Set<String> collect1 = stream.collect(Collectors.toSet());
        //收集到指定的集合中
        Stream<String> stream = Stream.of("a", "b");
        ArrayList<String> collect = stream.collect(Collectors.toCollection(ArrayList::new));
        //将流中的数据收集到数组中
        Stream<String> stream = Stream.of("a", "b");
        //Object[] objects = stream.toArray();
        String[] strings = stream.toArray(String[]::new);


对流中的数据进行聚合计算(相当于数据库中的聚合函数)

        Stream<Student> studentStream = Stream.of(
                new Student("小赵", 56, 11),
                new Student("小李", 33, 56),
                new Student("小王", 27, 7),
                new Student("小周", 87, 98)
        );

        // 获取最大值
        Optional<Student> max = studentStream.collect(Collectors.maxBy((s1, s2) -> s1.getAge() - s2.getAge()));
        System.out.println(max.get());

        //求和
        IntSummaryStatistics sum = studentStream.collect(Collectors.summarizingInt(s -> s.getAge()));
        System.out.println(sum);

        //求平均值
        Double score = studentStream.collect(Collectors.averagingInt(s -> s.getScore()));
        System.out.println(score);
        
        studentStream.collect(Collectors.counting());

对流中的数据进行分组

        Stream<Student> studentStream = Stream.of(
                new Student("小赵", 56, 11),
                new Student("小李", 56, 56),
                new Student("小王", 53, 7),
                new Student("小周", 53, 98)
        );
        //按照age分组
        Map<Integer, List<Student>> collect = studentStream.collect(Collectors.groupingBy(s -> s.getAge()));
        collect.forEach((k,v)-> System.out.println(k+":"+v));

        //成绩大于60合格,否则不合格
         Map<String, List<Student>> collect = studentStream.collect(Collectors.groupingBy(s -> {
            if (s.getScore() > 60) {
                return "合格";
            } else {
                return "不合格";
            }
        }));

        collect.forEach((k,v)-> System.out.println(k+":"+v));


分区,将流按照指定条件划分为不同区

        Stream<Student> studentStream = Stream.of(
                new Student("小赵", 56, 11),
                new Student("小李", 56, 56),
                new Student("小王", 53, 7),
                new Student("小周", 53, 98)
        );

        Map<Boolean, List<Student>> collect = studentStream.collect(Collectors.partitioningBy(s -> s.getScore() > 60));
        collect.forEach((k,v)->{
            System.out.println(k+"::"+v);
        });

拼接,将流中的字符串按照指定条件拼接成一个字符串

        
        String collect = studentStream.map(Student::getName).collect(Collectors.joining("-"));
        System.out.println(collect);
        //小赵-小李-小王-小周

五,并行stream流

并行stream流的速度较快

获取并行stream流的方法

1,将串行流改为并行流

        Stream<Integer> integerStream = Stream.of(2, 7, 45, 3, 19, 87, 12, 5);
        integerStream.parallel().forEach(s->{
            System.out.println(Thread.currentThread()+"---s:"+s);
        });

2,直接获取并行流

        List<Integer> list=new ArrayList<>();
        Collections.addAll(list,2, 7, 45, 3, 19, 87, 12, 5);
        list.parallelStream().forEach(s->{
            System.out.println(Thread.currentThread()+"---s:"+s);
    });

线程安全问题

        List<Integer> list = new ArrayList<>();
        IntStream.rangeClosed(1,1000).parallel().forEach(s-> {
            list.add(s);

        });
        System.out.println(list.size());
        //list.size!=1000,因为list是线程不安全的

解决方式

1,使用同步代码块

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

2,使用线程安全的集合,例如Vector
3,使用结合工具类将不安全的list转为安全的

        List<Integer> list = new ArrayList<>();
        List<Integer> list1 = Collections.synchronizedList(list);
        IntStream.rangeClosed(1,1000).parallel().forEach(s-> {

                list1.add(s);

        });
        System.out.println(list.size());

4,调用stream流的collect/toArray

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值