StreamUtils 是一个 Java Stream API 增强工具类,主要提供三类线程安全的集合操作方法:1) 支持 null 键的 Map 收集器(使用 LinkedHashMap 保持顺序),解决传统 toMap() 的 NPE 问题;2) 类型安全的列表转换方法,可选择生成可变或不可变列表;3) 列表转集合的自动去重功能。工具类采用静态方法设计,所有方法均可直接调用,特别解决了 Stream API 中常见的空指针和集合转换问题。其中 toMapWithNullKeys() 方法允许 null
package com.olivia.sdk.utils;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collector;
import java.util.stream.Collectors;
/**
* StreamUtils - Java Stream API增强工具类
*
* 该工具类提供了一系列用于简化集合操作的静态方法,主要包括:
* 1. 支持null键的Map收集器
* 2. 列表与集合的类型转换工具
* 3. 不可变集合与可变集合的安全转换
*
* 所有方法均为线程安全的静态方法,可直接通过类名调用。
* 设计目标是解决Java Stream API中常见的空指针问题和不可变集合转换问题。
*/
public class StreamUtils {
/**
* 将列表转换为Map,允许键为null值
*
* 与Collectors.toMap()不同,本方法不会在遇到null键时抛出NPE,
* 而是将null作为合法的键存入Map中。
*
* 注意:若列表中存在多个元素生成相同的键(包括null键),
* 后一个元素的值将覆盖前一个元素的值。
*
* @param <T> 列表元素类型
* @param <K> Map键的类型
* @param <U> Map值的类型
* @param list 待转换的列表
* @param keyMapper 键映射函数
* @param valueMapper 值映射函数
* @return 包含所有元素映射的LinkedHashMap(保持元素原始顺序)
*/
public static <T, K, U> Map<K, U> toMapWithNullKeys(List<T> list, Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper) {
return list.stream().collect(toMapWithNullKeys(keyMapper, valueMapper));
}
/**
* 创建一个支持null键的Map收集器
*
* 该收集器生成的Map实现为LinkedHashMap,能够保持元素的插入顺序。
* 适用于需要处理可能包含null键的流操作场景。
*
* @param <T> 流元素类型
* @param <K> Map键的类型
* @param <U> Map值的类型
* @param keyMapper 键映射函数
* @param valueMapper 值映射函数
* @return 支持null键的Map收集器
*/
public static <T, K, U> Collector<T, ?, Map<K, U>> toMapWithNullKeys(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper) {
return Collector.of(
LinkedHashMap::new, // 使用LinkedHashMap保持插入顺序
(map, element) -> {
K key = keyMapper.apply(element);
U value = valueMapper.apply(element);
map.put(key, value); // 直接允许null键
},
(left, right) -> {
left.putAll(right); // 合并时后添加的元素覆盖已有元素
return left;
},
Collector.Characteristics.IDENTITY_FINISH // 标识收集器的完成函数为恒等函数
);
}
/**
* 将一个列表转换为另一种类型的列表
*
* 该方法会生成一个不可变的列表,若需要可变列表,请使用重载方法并传入true参数。
*
* @param <I> 输入列表元素类型
* @param <R> 输出列表元素类型
* @param list 输入列表
* @param mapper 元素转换函数
* @return 转换后的不可变列表
*/
public static <I, R> List<R> list2List(List<I> list, Function<I, R> mapper) {
return list2List(list, mapper, false);
}
/**
* 将一个列表转换为另一种类型的列表,并可选择是否生成可变列表
*
* @param <I> 输入列表元素类型
* @param <R> 输出列表元素类型
* @param list 输入列表
* @param mapper 元素转换函数
* @param canModify 是否需要生成可变列表
* @return 转换后的列表(根据参数决定是否可变)
*/
public static <I, R> List<R> list2List(List<I> list, Function<I, R> mapper, boolean canModify) {
List<R> tl = list.stream().map(mapper).toList(); // Java 16+ 的toList()生成不可变列表
if (canModify) {
return new ArrayList<>(tl); // 包装为可变ArrayList
}
return tl; // 直接返回不可变列表
}
/**
* 将列表转换为集合,自动去重
*
* 该方法使用Collectors.toSet()生成集合,因此不保证元素顺序。
* 若需要有序集合,请使用Collectors.toCollection(LinkedHashSet::new)。
*
* @param <I> 输入列表元素类型
* @param <R> 输出集合元素类型
* @param list 输入列表
* @param mapper 元素转换函数
* @return 转换后的集合(无序,可能已去重)
*/
public static <I, R> Set<R> list2set(List<I> list, Function<I, R> mapper) {
return list.stream().map(mapper).collect(Collectors.toSet());
}
}
594

被折叠的 条评论
为什么被折叠?



