不使用distinct()方法基于Java 8 Stream API实现整数列表去重
问题:仅使用Java 8 Stream API、不调用
distinct()实现整数列表去重 题面要求:从整数列表中提取所有不重复元素,实现过程仅可使用Java 8 Stream API,禁止直接调用
distinct()方法。常规Stream去重直接调用distinct()是最简便的方案,但该路径被题目明确排除。
下面是几种可运行的实现方案,都是实际开发中常用的写法:
方案1:filter()配合Set记录已遍历元素(面试最高频写法)
核心是利用Set.add()方法的返回值特性:元素首次插入Set时返回true,元素已存在时返回false,刚好可以作为filter的放行判断条件。
import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.stream.Collectors; public class StreamDistinctDemo { public static List<Integer> getUniqueElements(List<Integer> originList) { Set<Integer> visited = new HashSet<>(); return originList.stream() .filter(num -> visited.add(num)) .collect(Collectors.toList()); } }
注意:这个写法在顺序流下完全没问题,如果要适配并行流,把new HashSet<>()替换成ConcurrentHashMap.newKeySet()避免线程安全问题即可。
方案2:利用Collectors.toMap()的键去重特性
Map本身不允许重复键,可以把元素本身作为Map的key,收集完成后取所有key就是去重后的结果:
import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; public class StreamDistinctDemo { public static List<Integer> getUniqueElements(List<Integer> originList) { return new ArrayList<>( originList.stream() .collect(Collectors.toMap( num -> num, num -> Boolean.TRUE, (oldVal, newVal) -> oldVal )).keySet() ); } }
这里第三个参数是重复key的合并策略,遇到重复元素直接保留已存在的key即可,不会抛出重复键的异常。
方案3:自定义收集器实现
如果想完全走Stream收集器链路,也可以直接把元素收集到Set中实现去重,再转成List返回:
import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; import java.util.stream.Collectors; public class StreamDistinctDemo { public static List<Integer> getUniqueElements(List<Integer> originList) { // 要保序就把HashSet换成LinkedHashSet return originList.stream() .collect(LinkedHashSet::new, LinkedHashSet::add, LinkedHashSet::addAll) .stream() .collect(Collectors.toList()); } }
这个写法本质和方案1逻辑一致,只是把状态判断封装到了收集器的累加逻辑里,并行流场景下会自动调用集合的addAll方法合并多个分片的结果,比方案1的filter写法更适配并行场景。
以上三种写法都没有调用Stream的
distinct()方法,保序场景下返回结果的元素顺序和原列表首次出现的顺序一致,和直接调用distinct()的去重效果完全一致。
内容的提问来源于stack exchange,提问作者Vijay
相关产品推荐
相关产品推荐

