Java8 Stream实战(二)

Java8 Stream实战(二)

前言

实际工作中,我们面临的数据处理场景异常复杂,往往需要多种API组合使用。对于常见的处理需求,Java8提供了例如 Collectors 来协助我们处理集合,比如我们需要将流收集成一个ArrayList 的时候,我们可以直接使用java.util.stream.Collectors#toList,如下

1
List collect = students.stream().collect(Collectors.toList());

但是 Collectors#toList 的实现相较于上面的函数式编程API,显得不那么简单明了,反而有些复杂:

1
2
3
4
public static <T> Collector<T, ?, List<T>> toList() {
return new CollectorImpl<>((Supplier<List<T>>) ArrayList::new, List::add,
(left, right) -> { left.addAll(right); return left; },
CH_ID);

对于源码这里就不过多介绍,本次主要是记录工作中一些常见的数据处理场景中,一起看看Stream是如何体现其优势的。

Stream in action

自定义分组

自定义分组(Map)的key & value

1
2
3
4
5
// 根据学生编号分组,value为学生的姓名
Map<String, List<String>> collect = students.stream().collect(Collectors.groupingBy(
Student::getStudentNo,
Collectors.mapping(Student::getName, Collectors.toList())));
collect.forEach((k, v) -> System.out.printf("studentNo: [%s], name: %s \n", k, v));

自定义去重

利用Set去重

1
2
3
4
5
6
7
@Test
public void generateTest2() {

Set<Student> collect = students.stream().collect(
Collectors.toCollection(
() -> new TreeSet<>(Comparator.comparing(Person::getId))));
}

上述是将 List 转换成 Set,从而利用 Set 的特性来完成去重,如果想收集的对象是 List ,可以参考下面代码:

1
2
3
4
List<Student> collect = students.stream().collect(Collectors.collectingAndThen(
Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(Student::getStudentNo))),
ArrayList::new));
collect.forEach(System.out::println);

List 转换 Map

工作中我们经常遇到根据ID 或者其他一些标识符将List转成Map的场景,对象的一个属性作为key,用来避免例如嵌套for循环。利用 Collectors#groupingBy 可以达到分组的效果,但是获取到的是 Map<K, List<V>> ,不方便我们使用,尽管有时候我们是根据主键(唯一)来分组,对于这样的key,只会存在一个value与之对应。那么我们如何获取到 Map<K, V> 呢,我们可以使用 Collectors#toMap ,JDK1.8中 toMap有三个重载方法,

1、如果能保证一个key只会对应一个value

1
2
3
4
Map<String, String> collect = STUDENTS.stream()
.collect(Collectors.toMap(Student::getStudentNo, Student::getName));

collect.forEach((k, v) -> System.out.printf("key: %s , value: %s \n", k, v));

2、如果一个key可能对应多个value(只保留其中一个value)

1
2
3
4
Map<String, String> collect = STUDENTS.stream().collect(Collectors.toMap(
Student::getStudentNo, Student::getName, (s1, s2) -> s1));

collect.forEach((k, v) -> System.out.printf("key: %s , value: %s \n", k, v));

3、如果一个key可能对应多个value(只保留其中一个value),但是想以非HashMap 来作为容器

1
2
3
4
Map<String, String> collect = STUDENTS.stream().collect(Collectors.toMap(
Student::getStudentNo, Student::getName, (s1, s2) -> s1, TreeMap::new));

collect.forEach((k, v) -> System.out.printf("key: %s , value: %s \n", k, v));
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×