Stream简介
Java 8 版本新增的Stream,配合同版本出现的Lambda ,给我们操作集合(Collection)提供了极大的便利。
Stream可以由数组或集合创建,对流的操作分为两种:
- 中间操作:每次返回一个新的流,可以有多个。
- 终端操作:每个流只能进行一次终端操作,终端操作结束后流无法再次使用。终端操作会产生一个新的集合或值。
创建Stream
-
通过 java.util.Collection.stream() 方法用集合创建流
List<String> list = Arrays.asList("a", "b", "c"); // 创建一个顺序流 Stream<String> stream = list.stream(); // 创建一个并行流 Stream<String> parallelStream = list.parallelStream();
-
使用 java.util.Arrays.stream(T[]array)方法用数组创建流
int[] array={1,3,5,6,8}; IntStream stream = Arrays.stream(array);
-
使用 Stream 的静态方法:of()、iterate()、generate()
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6); Stream<Integer> stream2 = Stream.iterate(0, (x) -> x + 3).limit(4); stream2.forEach(System.out::println); Stream<Double> stream3 = Stream.generate(Math::random).limit(3); stream3.forEach(System.out::println);
stream和 parallelStream的简单区分:
- stream是顺序流,由主线程按顺序对流执行操作
- parallelStream是并行流,内部以多线程并行执行的方式对流进行操作,但前提是流中的数据处理没有顺序要求。
Stream API
1、遍历/匹配(foreach/find/match)
List<Integer> list = Arrays.asList(7, 6, 9, 3, 8, 2, 1);
// 1.foreach
// 遍历输出符合条件的元素
list.stream().forEach(System.out::println);
// 2.find
// 匹配第一个
Optional<Integer> findFirst = list.stream().findFirst();
// 匹配任意(适用于并行流)
Optional<Integer> findAny = list.parallelStream().findAny();
// findFirst.get();
// findAny.get()
// 3.match
// 是否包含符合特定条件的元素
boolean anyMatch = list.stream().anyMatch(x -> x < 6);
2、按条件匹配filter
// 筛选员工中已满18周岁的人,并形成新的集合
List<Person> collect = personList.stream().filter(x -> x.getAge()>=18).collect(Collectors.toList());
3、聚合max、min、count
// 获取String集合中最长的元素
List<String> list = Arrays.asList("zhangsan", "lisi", "wangwu", "sunliu");
Optional<String> max = list.stream().max(comparator);
System.out.println(max);
// Optional[zhangsan]
List<Integer> list = Arrays.asList(1, 17, 27, 7);
Optional<Integer> max = list.stream().max(Integer::compareTo);
// 自定义排序
Optional<Integer> max2 = list.stream().max(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1.compareTo(o2);
}
});
System.out.println(max2);
// Optional[27]
4、map与flatMap
- map:接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
- flatMap:接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流。
// 整数数组每个元素+3
List<Integer> list = Arrays.asList(1, 17, 27, 7);
List<Integer> collect = list.stream().map(x -> x + 3).collect(Collectors.toList());
System.out.println(collect);
// [4, 20, 30, 10]
// 将两个字符数组合并成一个新的字符数组
String[] arr = {
"z, h, a, n, g", "s, a, n"};
List<String> list = Arrays.asList(arr);
System.out.println(list);
List<String> collect = list.stream().flatMap(x -> {
String[] array = x.split(",");
Stream<String> stream = Arrays.stream(array);
return stream;
}).collect(Collectors.toList());
System.out.println(collect);
// [z, h, a, n, g, s, a, n]
5、规约reduce
归约,也称缩减,顾名思义,是把一个流缩减成一个值,能实现对集合求和、求乘积和求最值操作。
// 求Integer集合的元素之和、乘积和最大值
List<Integer> list = Arrays.asList(1, 2, 3, 4);
//求和
Optional<Integer> reduce = list.stream().reduce((x,y) -> x+ y);
System.out.println("求和:"+reduce);
//求积
Optional<Integer> reduce2 = list.stream().reduce((x,y) -> x * y);
System.out.println("求积:"+reduce2);
//求最大值
Optional<Integer> reduce3 = list.stream().reduce((x,y) -> x>y?x:y);
System.out.println("求最大值:"+reduce3);
Optional<Integer> reduce = personList.stream().map(Person :: getSalary).reduce(Integer::sum);
Optional<Integer> reduce2 = personList.stream().map(Person :: getSalary).reduce(Integer::max);
System.out.println("工资之和:"+reduce);
System.out.println("最高工资:"+reduce2
6、collect
Collectors中用于数据统计的静态方法
- 计数: count
- 平均值: averagingInt、 averagingLong、 averagingDouble
- 最值: maxBy、 minBy
- 求和: summingInt、 summingLong、 summingDouble
- 统计以上所有: summarizingInt、 summarizingLong、 summarizingDouble
//Collectors.counting():统计员工人数
Long count = personList.stream().collect(Collectors.counting());
//Collectors.averagingDouble(Person::getSalary):求平均工资
Double average = personList.stream().collect(Collectors.averagingDouble(Person::getSalary));
//Collectors.maxBy(Integer::compare):求最高工资
Optional<Integer> max = personList.stream().map(Person::getSalary).collect(Collectors.maxBy(Integer::compare));
//Collectors.summingInt(Person::getSalary):求工资之和
Integer sum = personList.stream().collect(Collectors.summingInt(Person::getSalary));
//Collectors.summarizingDouble(Person::getSalary):一次性统计所有信息DoubleSummaryStatistics
DoubleSummaryStatistics collect = personList.stream().collect(Collectors.summarizingDouble(Person::getSalary));
收集(toList、toSet、toMap)
//collect(Collectors.toList());
//collect(Collectors.toSet());
// toMap
Map<String, Person> collect = personList.stream().filter(x -> x.getAge() > 18).collect(Collectors.toMap(Person::getName, y -> y));
System.out.println(collect);
分组(partitioningBy/groupingBy)
- 分区:将stream按条件分为两个 Map,比如员工按薪资是否高于8000分为两部分。
- 分组:将集合分为多个Map,比如员工按性别分组。有单级分组和多级分组。
// Collectors.partitioningBy(x -> x.getSalary() > 8000):将员工按薪资是否高于8000分组
Map<Boolean, List<Person>> part = personList.stream().collect(Collectors.partitioningBy(x -> x.getSalary() > 8000));
// Collectors.groupingBy(Person::getSex):将员工按性别分组
Map<String, List<Person>> group = personList.stream().collect(Collectors.groupingBy(Person::getSex));
// Collectors.groupingBy(Person::getSex, Collectors.groupingBy(Person::getArea)):将员工先按性别分组,再按地区分组
Map<String, Map<String, List<Person>>> group2 = personList.stream().collect(Collectors.groupingBy(Person::getSex, Collectors.groupingBy(Person::getArea)));
连接joining
joining可以将stream中的元素用特定的连接符(没有的话,则直接连接)连接成一个字符串。
String names = personList.stream().map(x->x.getName()),collect(Collectors.joining(","))
7、排序sorted
// .sorted(Comparator.comparing(Person::getSalary)):按工资升序排序(自然排序)
List<String> newList = personList.stream().sorted(Comparator.comparing(Person::getSalary)).map(Person::getName).collect(Collectors.toList());
// .sorted(Comparator.comparing(Person::getSalary).reversed():按工资倒序排序
List<String> newList2 = personList.stream().sorted(Comparator.comparing(Person::getSalary).reversed()).map(Person::getName).collect(Collectors.toList());
// .sorted(Comparator.comparing(Person::getSalary).thenComparing(Person::getAge)):先按工资再按年龄升序排序
List<String> newList3 = personList.stream().sorted(Comparator.comparing(Person::getSalary).thenComparing(Person::getAge)).map(Person::getName).collect(Collectors.toList());
// 先按工资再按年龄自定义排序(降序)
List<String> newList4 = personList.stream().sorted((p1, p2) -> {
if (p1.getSalary() == p2.getSalary()) {
return p2.getAge() - p1.getAge();
} else {
return p2.getSalary() - p1.getSalary();
}
}).map(Person::getName).collect(Collectors.toList());
8、提取/组合
合并、去重、限制、跳过等操作。
tring[] arr1 = {
"a", "b", "c", "d" };
String[] arr2 = {
"d", "e", "f", "g" };
Stream<String> stream1 = Stream.of(arr1);
Stream<String> stream2 = Stream.of(arr2);
// concat:合并两个流 distinct:去重
List<String> newList = Stream.concat(stream1, stream2).distinct().collect(Collectors.toList());
// limit:限制从流中获得前n个数据
List<Integer> collect = Stream.iterate(1, x -> x + 2).limit(10).collect(Collectors.toList());
// skip:跳过前n个数据
List<Integer> collect2 = Stream.iterate(1, x -> x + 2).skip(1).limit(5).collect(Collectors.toList());
List());
// limit:限制从流中获得前n个数据
List collect = Stream.iterate(1, x -> x + 2).limit(10).collect(Collectors.toList());
// skip:跳过前n个数据
List collect2 = Stream.iterate(1, x -> x + 2).skip(1).limit(5).collect(Collectors.toList());