文章目录
- 326. Java Stream API - 实现自定义的 `toList()` 与 `toSet()` 收集器
-
- 📦 实现一个自定义 `toList()` 收集器
- 🚀 使用我们的 `ToList` 收集器
- 🔄 将其改造成 `toSet()` 收集器
-
- ✅ 修改 1:使用 `HashSet` 作为容器
- ✅ 修改 2:声明该收集器是无序的
- ✅ 修改 1:使用 `HashSet` 作为容器
- 🧪 `ToSet` 收集器完整实现示例
- 🎯 总结一下关键点
- 🧠 小贴士
326. Java Stream API - 实现自定义的 toList() 与 toSet() 收集器
在 Java 的 Stream API 中,Collectors.toList() 和 Collectors.toSet() 是最常见的两个内置收集器。但你是否好奇它们背后的原理?今天我们就带大家手动实现一个行为等同于 toList() 的收集器,并了解如何基于它改造为 toSet() 收集器。
📦 实现一个自定义 toList() 收集器
1class ToList<T> implements Collector<T, List<T>, List<T>> { 2 3 @Override 4 public Supplier<List<T>> supplier() { 5 return ArrayList::new; // 创建一个空的 ArrayList 作为中间容器 6 } 7 8 @Override 9 public BiConsumer<List<T>, T> accumulator() { 10 return Collection::add; // 将元素累加到 List 中 11 } 12 13 @Override 14 public BinaryOperator<List<T>> combiner() { 15 return (list1, list2) -> { 16 list1.addAll(list2); // 合并两个 List(用于并行流) 17 return list1; 18 }; 19 } 20 21 @Override 22 public Function<List<T>, List<T>> finisher() { 23 return Function.identity(); // 直接返回中间容器,不需要额外转换 24 } 25 26 @Override 27 public Set<Characteristics> characteristics() { 28 return Set.of(Characteristics.IDENTITY_FINISH); // 说明 finisher 是 identity 29 } 30} 31
🚀 使用我们的 ToList 收集器
1Collection<String> strings = List.of("one", "two", "three", "four", "five"); 2 3List<String> result = strings.stream() 4 .collect(new ToList<>()); // 使用我们自定义的收集器 5 6System.out.println("result = " + result); 7
💡 输出结果:
1result = [one, two, three, four, five] 2
🔄 将其改造成 toSet() 收集器
我们只需要修改两处,就能实现一个等价于 Collectors.toSet() 的收集器:
✅ 修改 1:使用 HashSet 作为容器
1public Supplier<Set<T>> supplier() { 2 return HashSet::new; 3} 4
✅ 修改 2:声明该收集器是无序的
1public Set<Characteristics> characteristics() { 2 return Set.of( 3 Characteristics.IDENTITY_FINISH, 4 Characteristics.UNORDERED // 不保证处理顺序 5 ); 6} 7
🧪 ToSet 收集器完整实现示例
1class ToSet<T> implements Collector<T, Set<T>, Set<T>> { 2 3 @Override 4 public Supplier<Set<T>> supplier() { 5 return HashSet::new; 6 } 7 8 @Override 9 public BiConsumer<Set<T>, T> accumulator() { 10 return Set::add; 11 } 12 13 @Override 14 public BinaryOperator<Set<T>> combiner() { 15 return (set1, set2) -> { 16 set1.addAll(set2); 17 return set1; 18 }; 19 } 20 21 @Override 22 public Function<Set<T>, Set<T>> finisher() { 23 return Function.identity(); 24 } 25 26 @Override 27 public Set<Characteristics> characteristics() { 28 return Set.of( 29 Characteristics.IDENTITY_FINISH, 30 Characteristics.UNORDERED 31 ); 32 } 33} 34
🎯 总结一下关键点
| 元素 | toList() | toSet() |
|---|---|---|
| 容器类型 | ArrayList | HashSet |
| 是否无序 | ❌(有序) | ✅(无序) |
| 特性声明 | IDENTITY_FINISH | IDENTITY_FINISH, UNORDERED |
🧠 小贴士
- ✅ 想提升性能? 在能接受无序的场景中使用
UNORDERED。 - ✅ 想避免不必要的转换? 当
A和R类型一致时,记得声明IDENTITY_FINISH。 - ✅ 并行流支持? 如果想支持并行执行,还可以考虑加入
CONCURRENT特性(配合线程安全结构)。
《326. Java Stream API - 实现自定义的 toList() 与 toSet() 收集器》 是转载文章,点击查看原文。