Stream
什么是Stream
Stream将要处理的元素集合看作一种流,在流的过程中,借助Stream API对流中的元素进行操作,比如:筛选、排序、聚合等。
Stream可以由数组或集合创建,对流的操作分为两种:
- 中间操作,每次返回一个新的流,可以有多个。
- 终端操作,每个流只能进行一次终端操作,终端操作结束后流无法再次使用。终端操作会产生一个新的集合或值。
Stream 的创建
1、Collect.list() 方法。 如list.stream();
List<String> list = Arrays.asList("a", "b", "c");
// 创建一个顺序流
Stream<String> stream = list.stream();
// 创建一个并行流
Stream<String> parallelStream = list.parallelStream();
2、Arrays.Stream() 。 如 Arrays.stream({1,2,3,4,5});
int[] array={1,3,5,6,8};
IntStream stream = Arrays.stream(array);
3、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 类型
stream和parallelStream的简单区分: stream是顺序流,由主线程按顺序对流执行操作,而parallelStream是并行流,内部以多线程并行执行的方式对流进行操作,但前提是流中的数据处理没有顺序要求。例如筛选集合中的奇数,两者的处理不同之处:
stream 常用方法
遍历、匹配:foreach/find/match
List<Integer> list = Arrays.asList(7, 6, 9, 3, 8, 2, 1);
// 遍历输出符合条件的元素
list.stream().filter(x -> x > 6).forEach(System.out::println);
// 匹配第一个
Optional<Integer> findFirst = list.stream().filter(x -> x > 6).findFirst();
// 匹配任意(适用于并行流)
Optional<Integer> findAny = list.parallelStream().filter(x -> x > 6).findAny();
// 是否包含符合特定条件的元素
boolean anyMatch = list.stream().anyMatch(x -> x < 6);
System.out.println("匹配第一个值:" + findFirst.get());
System.out.println("匹配任意一个值:" + findAny.get());
System.out.println("是否存在大于6的值:" + anyMatch);
过滤:filter
int[] arrs = {1,2,3,4,5,6};
Arrays.stream(arrs).filter(x -> x>3).forEach(System.out::println);
结果: 4 5 6 (有换行符)
映射:map/flatmap
map 传入一个方法作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素
flatmap 传入方法作为参数,将流中的每个值都换成另一个流,最终合并一个新的集合
List<String> list = Arrays.asList("m-k-l-a", "1-3-5-7");
List<String> listNew = list.stream().flatMap(s -> {
// 将每个元素转换成一个stream
String[] split = s.split("-");
Stream<String> s2 = Arrays.stream(split);
return s2;
}).collect(Collectors.toList());
System.out.println("处理前的集合:" + list);
System.out.println("处理后的集合:" + listNew);
处理前的集合:[m-k-l-a, 1-3-5]
处理后的集合:[m, k, l, a, 1, 3, 5]
String[] strArr = { "abcd", "bcdd", "defde", "fTr" };
List<String> strList = Arrays.stream(strArr).map(String::toUpperCase).collect(Collectors.toList());
List<Integer> intList = Arrays.asList(1, 3, 5, 7, 9, 11);
List<Integer> intListNew = intList.stream().map(x -> x + 3).collect(Collectors.toList());
System.out.println("每个元素大写:" + strList);
System.out.println("每个元素+3:" + intListNew);
聚合:max/min/count
int[] arrs = {1,2,3,4,5,6};
OptionalInt max = Arrays.stream(arrs).max();
OptionalInt max = Arrays.stream(arrs).max();
OptionalInt min = Arrays.stream(arrs).min();
long count = Arrays.stream(arrs).count();
规约:reduce
public class Staff {
private String name;
private int salary;
public Staff(String name, int salary) {
this.name = name;
this.salary = salary;
}
// get/set 忽略
}
ArrayList<Staff> staffList = new ArrayList() {{
add(new Staff("zhangSan",10000));
add(new Staff("liSi",8000));
add(new Staff("wangWu",12000));
}};
//带初始值、累加器、合并器的reduce函数
Optional<Integer> reduce = staffList.stream().map(Staff::getSalary).reduce((sum, a) -> sum += a);
Integer reduce1 = staffList.stream().reduce(0, (sum, s) -> sum += s.getSalary(), (sum1, sum2) -> sum1 + sum2);
Integer reduce2 = staffList.stream().reduce(0, (sum, p) -> sum += p.getSalary(), Integer::sum);
System.out.println(reduce.get());
System.out.println(reduce1);
System.out.println(reduce2);
Integer maxSalary1 = staffList.stream().reduce(0, (max, p) -> max > p.getSalary() ? max : p.getSalary(), Integer::max);
Integer maxSalary2 = staffList.stream().reduce(0, (max, p) -> max > p.getSalary() ? max : p.getSalary(), (max1, max2) -> max1 > max2 ? max1 : max2);
System.out.println(maxSalary1);
System.out.println(maxSalary2);
集合:collect
toList/toSet/toMap
List<Integer> list = Arrays.asList(1, 6, 3, 4, 6, 7, 9, 6, 20);
List<Integer> listNew = list.stream().filter(x -> x % 2 == 0).collect(Collectors.toList());
Set<Integer> set = list.stream().filter(x -> x % 2 == 0).collect(Collectors.toSet());
Map<String, Staff> staffMap = staffList.stream().collect(Collectors.toMap(Staff::getName, p -> p));
拼接 joining
String names = staffList.stream().map(p -> p.getName()).collect(Collectors.joining(","));
归约(reducing)
排序(sorted)
-
sorted,中间操作。有两种排序:
- sorted():自然排序,流中元素需实现Comparable接口
- sorted(Comparator com):Comparator排序器自定义排序
ArrayList<Staff> staffList = new ArrayList() {{
add(new Staff("zhangSan",10000,20));
add(new Staff("liSi",8000,21));
add(new Staff("wangWu",12000,20));
add(new Staff("wangLiu",12000,22));
}};
//先按薪水降序,再按年龄升序
List<String> nameList = staff.stream().sorted(Comparator.comparing(Staff::getSalary).reversed().thenComparing(Staff::getAge)).map(Staff::getName).collect(Collectors.toList());
System.out.println(nameList);
// 自定义 薪水降序,年龄升序
List<String> nameCollect1 = staff.stream().sorted((p1, p2) -> {
if (p1.getSalary() == p2.getSalary()) {
return p1.getAge() - p2.getAge();
} else {
return p2.getSalary() - p1.getSalary();
}
}).map(Staff::getName).collect(Collectors.toList());
提取/组合
流也可以进行合并、去重、限制、跳过等操作。
String[] 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());
System.out.println("流合并:" + newList);
System.out.println("limit:" + collect);
System.out.println("skip:" + collect2);