如何用Java Stream更简洁实现去重列表?无需手动实例化集合
优化Java Stream去重列表的简洁写法
当然有更简洁高效的写法,完全不用手动创建ArrayList和显式return列表,而且性能比你当前的实现好很多,以下分几种场景给出方案:
场景1:可以修改BeanLevel类
如果能给BeanLevel重写equals()和hashCode()方法(基于id判断相等),直接用Stream自带的distinct()方法即可:
public static List<BeanLevel> sniff(List<BeanTask> tasks) { return tasks.stream() .map(task -> task.level) // 或者用BeanTask::getLevel(如果有getter方法) .distinct() .collect(Collectors.toList()); }
重写BeanLevel的equals和hashCode示例:
@Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; BeanLevel beanLevel = (BeanLevel) o; return id == beanLevel.id; } @Override public int hashCode() { return Objects.hash(id); }
场景2:不能修改BeanLevel类
如果无法修改BeanLevel的源码,用Collectors.toMap利用Map键的唯一性实现去重:
public static List<BeanLevel> sniff(List<BeanTask> tasks) { return tasks.stream() .map(task -> task.level) .collect(Collectors.toMap( BeanLevel::getId, // 用id作为Map的键 level -> level, // 用level本身作为值 (existing, newLevel) -> existing // 遇到重复键时保留已存在的对象 )) .values() // 取出所有去重后的level .stream() .collect(Collectors.toList()); }
这种写法全程用Stream操作串联,无需手动创建集合和添加元素,时间复杂度为O(n),比你原来每次遍历列表检查的O(n²)性能提升显著。
另外还有一种更轻量的写法,用HashSet跟踪已见过的id:
public static List<BeanLevel> sniff(List<BeanTask> tasks) { Set<Long> seenIds = new HashSet<>(); return tasks.stream() .map(task -> task.level) .filter(level -> seenIds.add(level.getId())) // add返回false则过滤重复项 .collect(Collectors.toList()); }
原实现的问题
你原来的代码在forEach中每次检查level是否存在时,都要遍历整个lst,数据量大时性能会很差;而上面的优化方案都是基于哈希表的O(1)查找,既简洁又高效,完全符合Stream的函数式编程风格。
内容的提问来源于stack exchange,提问作者Tugalsan Karabacak
相关产品推荐
相关产品推荐

