当前位置: 首页 > news >正文

java:创建指定容器类型(如ImmutableSet)的Collector对象

之前对java 8的stream的理解只停留于基本的使用,比如将一个stream转为set,就直接用Collectors.toSet()

String[] array = new String[]{"hello","world"};
Stream.of(array).collect(Collectors.toSet());

这里,Collectors.toSet()提供的Collector实例将stream转为HashSet,

如果只是希望改变输出的集合类型,比如TreeSet,那也不复杂,用Collectors.toCollection方法就能实现:

String[] array = new String[]{"hello","world"};
Stream.of(array).collect(Collectors.toCollection(TreeSet<String>::new));

但如果要转为不可变集合呢?
最近需要通过流创建指定类型的Map,Set,List,才对java.util.stream.Collector有了更多的了解:

java.util.stream.Collector提供了两个参数不同的of静态方法,用于创建Collector接口实例,
其中有finisher参数的方法可以帮助我解决这个问题:

	/**** 类型参数:* <T> 新收集器的输入元素类型* <A>新型收集器的中间类型* <R> 新收集器的最终结果类型* 参数:* supplier 新收集器的供应商功能* accumulator 新收集器的累加器函数* combiner 新收集器的合并器函数* finisher 新收集器的终结器函数* characteristics 新收集器的收集器特性*/public static<T, A, R> Collector<T, A, R> of(Supplier<A> supplier,BiConsumer<A, T> accumulator,BinaryOperator<A> combiner,Function<A, R> finisher,Characteristics... characteristics) {}

示例1:不可变的LinkedHashSet

我们将一个Set转为不可变集合可以用java.util.Collections.unmodifiableSet方法,但如何指定呢?了解上面这个方法用作用,就可以如下实现

/** 创建一个Collector实例,将stream中的元素转为LinkedHashSet,并包装为不可变对象 */
Collector.of(LinkedHashSet::new,                                          // supplierSet::add,                                              // accumulator(left, right) -> { left.addAll(right); return left; }, // combinera->(Set<T>)Collections.unmodifiableSet(a)              // Collections.unmodifiableSet方法作finisher);

这里关键就是用到了finisher参数,通过这个参数将最后的LinkedHashSet对象通过Collections.unmodifiableSet方法封装为不可变对象

示例2:ImmutableSet

guava库的ImmutableSet对象的创建过程一般如下,先创建一个Builder,将元素添加到Builder,最后再用Builder对象生成ImmutableSet对象:

ImmutableSet.<String>Builder builder = ImmutableSet.builder();
builder.add("hello").add("world");
ImmutableSet<String> set = builder.build();

是否也能用Collector.of方法创建ImmutableSet对象呢?

前面这个Collector.of方法中有三个类型参数T, A, R,其中A中间类型,R才是最终结果类型,那么当下这个场合,我们将ImmutableSet.Builder理解为中间结果类型,就知道Collector.of方法该怎么用了:

Collector.of(ImmutableSet.Builder<T>::new,                  // supplier 提供ImmutableSet.Builder对象作为中间结果对象ImmutableSet.Builder::add,                     // accumulator 在中间结果对象上实现累加(left, right) -> left.addAll(right.build()),   // combinerImmutableSet.Builder::build                    // 使用ImmutableSet.Builder.build()方法当作finisher);

示例3:Map

有了上面的经验,创建Map也是差不多的方式,如下方法返回一个Collector实例,将stream中元素转为不可修改的LinkedHashMap:

public static <T, K, U> Collector<T, ?, Map<K,U>> toLinkedHashMap(Function<? super T, ? extends K> keyMapper,Function<? super T, ? extends U> valueMapper) {return Collector.of(LinkedHashMap<K,U>::new,                             // supplier(map, element) -> map.put(                           // accumulatorkeyMapper.apply(element),valueMapper.apply(element)),(left, right) -> {left.putAll(right); return left;}, // combinera->(Map<K,U>)Collections.unmodifiableMap(a)          // Collections.unmodifiableMap方法作finisher);
}

CollectorSupport

如此,可以实现一个通用工具类CollectorSupport ,提供常用容器类型的Collector实例

CollectorSupport .java

import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.function.Function;
import java.util.stream.Collector;
import java.util.stream.Collectors;import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;/*** 收集器支持类,提供一系列便捷方法用于创建不同类型的收集器<p>* 可用于将流元素收集到各种集合或映射中,包括不可变集合、有序集合和排序集合等。* @author guyadong* @since 2.1.0*/
public class CollectorSupport {/*** 创建一个用于将流元素收集到{@link ImmutableList}的收集器的便利方法<p>* 该收集器会将流中的元素添加到{@link ImmutableList.Builder}中,最终构建为不可变的{@link ImmutableList}。* * @param <T> 流中元素的类型* @return 一个新的收集器实例,可将流元素收集到{@link ImmutableList}中*/public static <T> Collector<T, ?, ImmutableList<T>> toImmutableList() {return Collector.of(ImmutableList.Builder<T>::new,                // supplierImmutableList.Builder::add,                   // accumulator(left, right) -> left.addAll(right.build()),  // combinerImmutableList.Builder::build                  // finisher);}/*** 创建一个用于将流元素收集到{@link ImmutableSet}的收集器的便利方法<p>* 该收集器会将流中的元素添加到{@link ImmutableSet.Builder}中,最终构建为不可变的{@link ImmutableSet}集合。* * @param <T> 流中元素的类型* @return 一个新的收集器实例,可将流元素收集到{@link ImmutableSet}中*/public static <T> Collector<T, ?, ImmutableSet<T>> toImmutableSet() {return Collector.of(ImmutableSet.Builder<T>::new,                  // supplierImmutableSet.Builder::add,                     // accumulator(left, right) -> left.addAll(right.build()),   // combinerImmutableSet.Builder::build                    // finisher);}/*** 创建一个用于将流元素收集到{@link ImmutableMap}的收集器的便利方法<p>* 该收集器使用指定的键映射函数和值映射函数将流元素转换为键值对,<br>* 最终返回的映射为不可修改的{@link ImmutableMap}类型。* * @param <T> 流中元素的类型* @param <K> 映射键的类型* @param <V> 映射值的类型* @param keyMapper 用于从流元素中提取键的映射函数* @param valueMapper 用于从流元素中提取值的映射函数* @return 一个新的收集器实例,可将流元素收集到{@link ImmutableMap}中*/public static <T, K, V> Collector<T, ?, ImmutableMap<K, V>> toImmutableMap(Function<? super T, ? extends K> keyMapper,Function<? super T, ? extends V> valueMapper) {return Collector.of(ImmutableMap.Builder<K, V>::new,             // supplier(builder, element) -> builder.put(           // accumulatorkeyMapper.apply(element),valueMapper.apply(element)),(left, right) -> left.putAll(right.build()), // combinerImmutableMap.Builder::build                  // finisher);}/*** 创建一个用于将流元素收集到{@link LinkedHashSet}的收集器的便利方法<p>* 该收集器会保持元素插入的顺序,返回的集合为{@link LinkedHashSet}类型。<br>* 可通过参数指定返回的集合是否为不可修改的{@link Set}视图。* * @param <T> 流中元素的类型* @param unmodifiable 如果为{@code true},则返回的集合为不可修改的{@link Set}视图* @return 一个新的收集器实例,可将流元素收集到{@link LinkedHashSet}中*/@SuppressWarnings("unchecked")public static <T> Collector<T, ?, Set<T>> toLinkedHashSet(boolean unmodifiable) {if(unmodifiable) {return Collector.of(LinkedHashSet::new,                                    // supplierSet::add,                                              // accumulator(left, right) -> { left.addAll(right); return left; }, // combinera->(Set<T>)Collections.unmodifiableSet(a)              // finisher);			}return Collectors.toCollection(LinkedHashSet::new);}/*** 创建一个用于将流元素收集到{@link TreeSet}的收集器的便利方法<p>* 该收集器会根据元素的自然顺序对元素进行排序,若遇到重复元素会自动去重,<br>* 最终返回的集合类型为{@link TreeSet}。<br>* 可通过{@code unmodifiable}参数指定返回的集合是否为不可修改的视图。* * @param <T> 流中元素的类型* @param unmodifiable 如果为{@code true},则返回的集合为不可修改的{@link Set}视图* @return 一个新的收集器实例,可将流元素收集到{@link TreeSet}中*/@SuppressWarnings("unchecked")public static <T> Collector<T, ?, Set<T>> toTreeSet(boolean unmodifiable) {if(unmodifiable) {return Collector.of(TreeSet::new,                                          // supplierSet::add,                                              // accumulator(left, right) -> { left.addAll(right); return left; }, // combinera->(Set<T>)Collections.unmodifiableSet(a)              // finisher);}return Collectors.toCollection(TreeSet::new);}/**/*** 创建一个用于将流元素收集到{@link LinkedHashMap}的收集器的便利方法<p>* 该收集器会保持元素插入的顺序,使用指定的键映射函数和值映射函数将流元素转换为键值对,<br>* 若遇到重复键,后面的值会覆盖前面的值,最终返回的映射为{@link LinkedHashMap}类型。* * @param <T> 流中元素的类型* @param <K> 映射键的类型* @param <U> 映射值的类型* @param keyMapper 用于从流元素中提取键的映射函数* @param valueMapper 用于从流元素中提取值的映射函数* @param unmodifiable 如果为{@code true},则返回的映射为不可修改的{@link Map}视图* @return 一个新的收集器实例,可将流元素收集到{@link LinkedHashMap}中*/public static <T, K, U> Collector<T, ?, Map<K,U>> toLinkedHashMap(Function<? super T, ? extends K> keyMapper,Function<? super T, ? extends U> valueMapper,boolean unmodifiable) {if(unmodifiable) {return Collector.of(LinkedHashMap<K,U>::new,                             // supplier(map, element) -> map.put(                           // accumulatorkeyMapper.apply(element),valueMapper.apply(element)),(left, right) -> {left.putAll(right); return left;}, // combinera->(Map<K,U>)Collections.unmodifiableMap(a)          // finisher);}return Collectors.toMap(keyMapper, valueMapper, (u,v) -> { throw new IllegalStateException(String.format("Duplicate key %s", u)); }, LinkedHashMap::new);}/*** 将元素收集到一个{@link TreeMap}中。<br>* <p>使用指定的键映射函数和值映射函数将输入元素转换为键值对,添加到{@link TreeMap}中。</p>* <p>可以指定是否返回不可修改的映射。</p>* * @param <T> 输入元素的类型* @param <K> 映射键的类型* @param <U> 映射值的类型* @param keyMapper 用于从输入元素中提取键的映射函数* @param valueMapper 用于从输入元素中提取值的映射函数* @param unmodifiable 是否返回不可修改的映射,true表示返回不可修改的映射,false表示返回普通的{@link TreeMap}* @return 一个{@link Collector}实例,用于将输入元素收集到{@link TreeMap}中*/public static <T, K, U> Collector<T, ?, Map<K,U>> toTreeMap(Function<? super T, ? extends K> keyMapper,Function<? super T, ? extends U> valueMapper,boolean unmodifiable) {if(unmodifiable) {return Collector.of(TreeMap<K,U>::new,                                   // supplier(map, element) -> map.put(                           // accumulatorkeyMapper.apply(element),valueMapper.apply(element)),(left, right) -> {left.putAll(right); return left;}, // combinera->(Map<K,U>)Collections.unmodifiableMap(a)          // finisher);}return Collectors.toMap(keyMapper, valueMapper, (u,v) -> { throw new IllegalStateException(String.format("Duplicate key %s", u)); }, TreeMap::new);}
}
http://www.xdnf.cn/news/1298503.html

相关文章:

  • Redis (REmote DIctionary Server) 高性能数据库
  • 设计模式笔记_行为型_状态模式
  • OpenAI 的浏览器将使用 ChatGPT Agent 来控制浏览器
  • 记录一些奇奇怪怪的面试题
  • 【慕伏白】CTFHub 技能树学习笔记 -- 基础知识 签到
  • AI 编程实践:用 Trae 快速开发 HTML 贪吃蛇游戏
  • 【软考中级网络工程师】知识点之常用网络诊断和配置命令
  • 机器学习核心概念与实践笔记
  • 解刨HashMap的put流程 <二> JDK 1.8
  • Redis 03 redis 缓存异常
  • Oracle commit之后做了什么
  • OS设备UDID查看方法
  • word——删除最后一页空白页
  • centos部署chrome和chromedriver
  • 【C++】细说继承(2w字详解)
  • OpenCV对椒盐处理后的视频进行均值滤波处理
  • 基于机器学习的文本情感极性分析系统设计与实现
  • [论文阅读] 人工智能 + 软件工程 | 代码变更转自然语言生成中的幻觉问题研究解析
  • 爬虫逆向--Day15--核心逆向案例2(Python逆向实现请求加密、请求堆栈、拦截器关键字)
  • PostgreSQL 免安装
  • SQL详细语法教程(三)mysql的函数知识
  • ActionChains 鼠标操作笔记
  • PyCharm 2025.2:面向工程师的 AI 工具
  • IDEA、Pycharm、DataGrip等激活破解冲突问题解决方案之一
  • C# 中 ArrayList动态数组、List<T>列表与 Dictionary<T Key, T Value>字典的深度对比
  • 20道Vue框架相关前端面试题及答案
  • OpenCV ------图像基础处理(一)
  • Elasticsearch ABAC 配置:基于患者数据的动态访问控制
  • Exif.js获取手机拍摄照片的经纬度
  • 风电功率预测实战:从数据清洗到时空建模​​