对流操作完成以后,如果需要将流的结果保存到数组或集合中,可以收集流中的数据
将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列表
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());
}