Java Stream中自定义Collector实现复杂数据收集的方法
作者:码到三十五
1. Collector接口的作用
Collector
接口定义了数据收集、转换和聚合的基本操作,使得从Stream中收集到特定的数据结构或执行复杂的聚合操作成为可能。Collector
接口为Stream操作提供了一个终止方法,将Stream的处理结果收集到一个特定的容器中。
2. Collector接口的组成
Collector
接口包含以下五个主要方法:
supplier():返回一个新的结果容器的
Supplier
。这个方法用于创建用于存储收集结果的容器。accumulator():接收一个结果容器和一个流中的元素,将元素添加到结果容器中。这是累积元素的核心方法,用于将流中的元素逐个添加到结果容器中。
combiner():接收两个结果容器,合并它们。在并行流处理中,如果有多个结果容器被生成,则使用
combiner()
方法将它们合并为一个容器。finisher():接收一个结果容器,返回最终结果。这个方法通常用于将结果容器转换为最终想要的形式,例如,对容器中的元素进行排序或过滤。
characteristics():返回一个不可变的Set,包含收集器的特性。这些特性用于优化流处理过程,如并行流处理或结果的无序性。
3. Collector接口的工作原理
Collector
接口的工作原理基于上述五个方法的协作。先通过supplier()
方法创建一个新的结果容器。然后,遍历Stream中的每个元素,使用accumulator()
方法将元素添加到结果容器中。在并行流处理中,如果有多个结果容器被生成,则使用combiner()
方法将它们合并为一个容器。最后,通过finisher()
方法将结果容器转换为最终想要的形式,并返回。
4. Collector的预定义实现Collectors
Collectors可以看做是Collector接口的实现工厂,提供了多个用于数据收集、转换和聚合的预定义收集器,如toList()、toSet()、toMap()、joining()、counting()、summingInt()、averagingInt()等。这些收集器利用Collector接口实现,使得从Stream中收集数据变得更为方便和高效。
List<String> list = Stream.of("a", "b", "c") .collect(Collectors.toList()); Map<Character, List<String>> grouped = Stream.of("a", "b", "c") .collect(Collectors.groupingBy(s -> s.charAt(0))); String joined = Stream.of("a", "b", "c") .collect(Collectors.joining(", "));
如,toList()收集器通过调用new ArrayList<>()来创建一个新的结果容器,并使用accumulator()方法将流中的元素添加到结果容器中。toMap()收集器则创建一个新的HashMap,并使用提供的键函数和值函数将元素映射到Map的键和值上。
5. 自定义Collector的使用场景
通过实现Collector
接口来自定义复杂的收集器,以满足特定的数据处理需求。自定义Collector
时,要实现上述五个方法,并定义如何收集、转换和聚合数据。
如,自定义Collector
对Person
对象进行排序,并根据特定条件进行分组:
public static class CustomCollector<T> implements Collector<Person, List<Person>, Map<String, List<Person>>> { @Override public Supplier<List<Person>> supplier() { return ArrayList::new; } @Override public BiConsumer<List<Person>, Person> accumulator() { return (list, person) -> list.add(person); } @Override public BinaryOperator<List<Person>> combiner() { return (list1, list2) -> { list1.addAll(list2); return list1; }; } @Override public Function<List<Person>, Map<String, List<Person>>> finisher() { return list -> { Map<String, List<Person>> result = new HashMap<>(); // 自定义排序规则 list.sort((p1, p2) -> { if (p1.age != null && p2.age != null) { return p1.age.compareTo(p2.age); } else if (p1.age != null) { return -1; } else if (p2.age != null) { return 1; } else { return p1.name.compareTo(p2.name); } }); // 自定义分组规则 for (Person person : list) { if (result.containsKey(person.name.substring(0, 2))) { result.get(person.name.substring(0, 2)).add(person); } else { List<Person> group = new ArrayList<>(); group.add(person); result.put(person.name.substring(0, 2), group); } } return result; }; } @Override public Set<Collector.Characteristics> characteristics() { return EnumSet.of(Collector.Characteristics.IDENTITY_FINISH); } }
自定义收集、转换和聚合Person
对象的逻辑。使用自定义的排序和分组规则,根据姓名和年龄将Person
对象分组并排序,最终返回Map<String, List<Person>>
。
通过自定义Collector
,创建特定的收集器,而满足复杂的数据处理需求。
使用方法:
import java.util.*; public class CustomCollectorDemo { public static void main(String[] args) { List<Person> people = Arrays.asList( new Person("Alice", 25), new Person("Bob", 23), new Person("Charlie", 28), new Person("David", 25), new Person("Eva", 23), new Person("Frank", 28) ); Map<String, List<Person>> result = people.stream() .collect(new CustomCollector<>()); System.out.println(result); } static class Person { String name; Integer age; ... } }
到此这篇关于Java Stream中自定义Collector实现复杂数据收集的方法的文章就介绍到这了,更多相关Java Stream自定义Collector数据收集内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!