JDK8 Lambda表达式之Stream高级用法(六)

3,264 阅读3分钟

对流操作完成以后,如果需要将流的结果保存到数组或集合中,可以收集流中的数据

将Stream流中的结果到集合中

Stream流提供collect方法,其参数需要一个java.util.stream.Collector<T, A, R>接口对象来指定收集到那种结合中.java.util.stream.Collectors类提供一些方法,可以作为Collecto接口的实例:

  • public static <T> Collector<T, ?, List<T>> toList();转换为List集合
  • public static <T> Collector<T, ?, List<T>> toSet();转换为Set集合
public void testStreamToCollection(){
        List<String> one = new ArrayList<>();
        Collections.addAll(one ,"赵信", "武则天", "虞姬","项羽","干将莫邪");
        //将流中的集合收集到集合中
        List<String> toList = one.stream().collect(Collectors.toList());
        Set<String> toSet = one.stream().collect(Collectors.toSet());
   			//收集到指定的集合中
        ArrayList<String> arrList = one.stream().collect(Collectors.toCollection(ArrayList::new));
        HashSet<String> hashSet = one.stream().collect(Collectors.toCollection(HashSet::new));
  			//将流中的集合收集到数组中
        String[] array = one.stream().toArray(String[]::new);
    }

对流中的数据进行聚合计算

当我们使用Stream 流处理数据后, 可以像数据库的聚合函数一样对某个字段进行操作. 比如获取最大值、最小值、总和、平均值、统计数量等.

public void testStreamToOther(){
        Stream<Person> personStream = Stream.of(
                new Person("貂蝉", 18),
                new Person("王昭君", 21),
                new Person("西施", 19),
                new Person("杨玉环", 20));
        //获取最大值
        Optional<Person> max = personStream.collect(Collectors.maxBy((s1, s2) -> s1.getAge() - s2.getAge()));
        //最小值
        Optional<Person> min = personStream.collect(Collectors.minBy((s1, s2) -> s1.getAge() - s2.getAge()));
        //求和
        Integer sum = personStream.collect(Collectors.summingInt(s -> s.getAge()));
        //平均值
        Double avg = personStream.collect(Collectors.averagingInt(s -> s.getAge()));
        //统计数量
        Long count = personStream.collect(Collectors.counting());
    }
}

对流中数据进行分组

当我们使用Stream流处理数据后,可以根据某个属性将数据分组:

public void testStreamGroup(){
        Stream<Person> personStream = Stream.of(
                new Person("貂蝉", 18),
                new Person("王昭君", 20),
                new Person("西施", 19),
                new Person("杨玉环", 20));
        //按年龄分组
        Map<Integer, List<Person>> ageMap = personStream.collect(Collectors.groupingBy(s -> s.getAge()));
        Map<Integer, List<Person>> ageMap2 = personStream.collect(Collectors.groupingBy(Person::getAge));
        //按年龄大小
        Map<String, List<Person>> ageMap3 = personStream.collect(Collectors.groupingBy(e -> {
            if (e.getAge() > 19) {
                return "年轻";
            } else {
                return "年长";
            }
        }));
    }

对流中数据进行多级分组

public void testStreamGroup2(){
        Stream<Person> personStream = Stream.of(
                new Person("貂蝉", 19),
                new Person("王昭君", 20),
                new Person("西施", 19),
                new Person("杨玉环", 20));
        //先根据年龄分组,在根据姓名分组
        //groupingBy(Function<? super T, ? extends K> classifier,Collector<? super T, A, D> downstream)
        Map<Integer, Map<String, List<Person>>> collect = personStream.collect(Collectors.groupingBy(Person::getAge,
                Collectors.groupingBy(e -> {
            if (e.getAge() > 19) {
                return "年轻";
            } else {
                return "年长";
            }
        })));
        System.out.println("collect:"+collect.toString());
    }

对流中的数据进行分区

Collectors.partitioningBy 会根据是否为true,把集合分割成两个列表,一个true列表,一个false列表 image20200814081804388.png

public void testStreamPartition(){
        Stream<Person> personStream = Stream.of(
                new Person("貂蝉", 19),
                new Person("王昭君", 20),
                new Person("西施", 19),
                new Person("杨玉环", 20));
        Map<Boolean, List<Person>> collect = personStream.collect(Collectors.partitioningBy(e -> {
            return e.getAge() > 19;
        }));
        System.out.println("collect:"+collect.toString());
    }

对流中的数据进行拼接

Collectors.joining会根据指定的连接符,将所有元素连接成一个字符串.

public void testJoin(){
        Stream<Person> personStream = Stream.of(
                new Person("貂蝉", 19),
                new Person("王昭君", 20),
                new Person("西施", 19),
                new Person("杨玉环", 20));
        //根据一个字符串拼接
        String names = personStream.map(Person::getName).collect(Collectors.joining("_"));
        //根据三个字符串拼接,分隔符,前缀后缀
        personStream.map(Person::getName).collect(Collectors.joining("_","AA","BB"));
        System.out.println("names:"+names);
    }

并行的Stream流

串行的Stream流

    public void testSerial(){
        Stream.of(1,4,6,7,8,9,2,3).filter(e->{
            System.out.println(Thread.currentThread()+"::"+e);
            return e>3;
        }).count();
    }

Thread[main,5,main]::1
Thread[main,5,main]::4
Thread[main,5,main]::6
Thread[main,5,main]::7
Thread[main,5,main]::8
Thread[main,5,main]::9
Thread[main,5,main]::2
Thread[main,5,main]::3

并行的Stream流

public void testParallelStream(){
       ArrayList<Object> list = new ArrayList<>();
       //直接获取并行的stream流
       Stream<Object> stream = list.parallelStream();
       //将串行流变成并行流
       Stream<Object> parallel = list.stream().parallel();

       Stream.of(1,4,6,7,8,9,2,3).parallel().filter(e->{
           System.out.println(Thread.currentThread()+"::"+e);
           return e>3;
       }).count();
   }

Thread[ForkJoinPool.commonPool-worker-1,5,main]::6
Thread[ForkJoinPool.commonPool-worker-2,5,main]::4
Thread[ForkJoinPool.commonPool-worker-2,5,main]::3
Thread[ForkJoinPool.commonPool-worker-3,5,main]::7
Thread[ForkJoinPool.commonPool-worker-2,5,main]::2
Thread[ForkJoinPool.commonPool-worker-3,5,main]::8
Thread[ForkJoinPool.commonPool-worker-1,5,main]::1
Thread[main,5,main]::9

解决parallelStream线程安全问题

public void testParallelStreamNotice(){
        List<Integer> list = new ArrayList<>();
        IntStream.rangeClosed(0,1000).parallel().forEach( e->{
            list.add(e);
        });
        System.out.println("list:"+list.size());
        //解决parallelStream线程安全问题方案一:使用同步代码块
        Object obj = new Object();
        IntStream.rangeClosed(0,1000).parallel().forEach( e->{
            synchronized (obj){
                list.add(e);
            }
        });
        //方案二:使用线程安全的集合
        //Vector<Integer> list2 = new Vector<>();
        Collection<Integer> synchronizedList = Collections.synchronizedCollection(list);
        IntStream.rangeClosed(0,1000).parallel().forEach( e->{
            synchronizedList.add(e);
        });
        //方案三:调用stream的collect/toArray 方法
        List<Integer> collect = IntStream.rangeClosed(0, 1000).parallel().boxed().collect(Collectors.toList());
    }