HashSet本身不提供过滤功能,需借助Stream API的filter()创建新集合或使用removeIf()就地移除;自定义对象须重写equals()和hashCode()以确保过滤正确。

HashSet 本身不提供“过滤”功能,它是一个无序、不允许重复的集合,主要用来快速存取和去重。要“过滤掉不需要的数据项”,实际是通过外部逻辑筛选出符合条件的元素,再构建新集合或就地移除——关键在于结合 Java 的集合操作和 Lambda 表达式(Java 8+)。
用 stream().filter() 创建新 HashSet
这是最常用、最安全的方式:不修改原集合,生成一个只含所需元素的新 HashSet。
- 调用 stream() 将 HashSet 转为流
- 用 filter() 传入 Predicate(比如排除 null、长度小于 3 的字符串、非正数等)
- 用 collect(Collectors.toCollection(HashSet::new)) 收集回 HashSet
Set<String> original = new HashSet<>(Arrays.asList("a", "bb", "ccc", "dddd"));
Set<String> filtered = original.stream()
.filter(s -> s != null && s.length() >= 3)
.collect(Collectors.toCollection(HashSet::new));
用 removeIf() 就地移除(注意并发修改风险)
直接在原 HashSet 上删除不满足条件的元素,简洁高效,但不能在遍历中手动调用 remove(),必须用 removeIf。
- 传入的 Predicate 返回 true 的元素会被移除
- 内部已处理迭代器安全问题,无需额外同步(单线程下安全)
- 多线程环境需额外加锁或改用 ConcurrentSkipListSet 等线程安全集合
original.removeIf(s -> s == null || s.trim().isEmpty());
立即学习“Java免费学习笔记(深入)”;
自定义对象需确保正确重写 equals() 和 hashCode()
如果 HashSet 存的是自定义类(如 User),过滤逻辑依赖于对象是否被正确识别为“相同”。若没重写这两个方法,即使字段值一样,filter 或 removeIf 也可能失效。
- 比如用 filter 想去掉 age
- IDE(如 IntelliJ)可一键生成这两个方法,字段选中后即可
避免常见陷阱
- 别在 for-each 循环里调用 remove():会抛 ConcurrentModificationException
- filter 后不 collect → 流就结束了:漏掉 collect 会导致无任何结果
- HashSet 不保证顺序:如果过滤后需要有序结果,考虑用 LinkedHashSet 或先转 List 再排序


















