Java Stream调用distinct后仍存在重复元素问题咨询
Stream的distinct()对自定义对象去重失效问题
我的处理逻辑:
- 生成元素流
- 把每个元素映射为列表流
- 合并列表流为单个流
- 去除重复元素
- 对每个元素应用map函数并收集成列表
但实际跑起来步骤4的去重根本没生效,下面是测试代码和运行结果:
public class test { public static void main(String[] args) { List<TestBean> obj_list = Arrays.asList(new TestBean("aa"), new TestBean("bb" ), new TestBean("bb")).stream() .distinct().map(tt -> { tt.col = tt.col + "_t"; return tt; }).collect(Collectors.toList()); System.out.println(obj_list); List<String> string_obj_list = Arrays.asList(new String("1"), new String("2"), new String("2")).stream().distinct().map(t -> t + "_t").collect(Collectors.toList()); System.out.println(string_obj_list); List<String> string_list = Arrays.asList("1", "2", "2").stream().distinct().map(t -> t + "_t").collect(Collectors.toList()); System.out.println(string_list); } } @Data @AllArgsConstructor @EqualsAndHashCode class TestBean { String col; }
运行结果:
[TestBean(col=aa_t), TestBean(col=bb_t), TestBean(col=bb_t)] [1_t, 2_t] [1_t, 2_t]
问题出在哪
自定义对象的equals/hashCode没写对:
你的TestBean如果是非静态内部类,Lombok自动生成的equals和hashCode会带上外部类的实例引用,这就导致两个TestBean("bb")哪怕col一样,也会被判定成不同的对象,distinct()自然过滤不掉重复。
另外,如果Lombok的注解没生效(比如依赖没加对、版本有问题),也会导致equals和hashCode不是基于col生成的,去重肯定失效。对象修改的小陷阱(不是直接原因,但容易搞混):
你在map里直接改了原对象的col属性,但distinct()是在map之前执行的,这个修改不会影响去重逻辑,只是会让保留下来的对象属性变了,但这不是去重失效的根因。
怎么解决
修正自定义类的相等性判断:
- 如果
TestBean是内部类,必须加static修饰,避免外部类实例干扰:@Data @AllArgsConstructor @EqualsAndHashCode static class TestBean { String col; } - 或者手动写
equals和hashCode,确保只看col字段:class TestBean { String col; public TestBean(String col) { this.col = col; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; TestBean testBean = (TestBean) o; return Objects.equals(col, testBean.col); } @Override public int hashCode() { return Objects.hash(col); } @Override public String toString() { return "TestBean(col=" + col + ")"; } }
- 如果
别改原对象,创建新对象:
函数式编程尽量别搞副作用,map的时候新建一个TestBean实例,既避免意外问题,也更规范:List<TestBean> obj_list = Arrays.asList(new TestBean("aa"), new TestBean("bb"), new TestBean("bb")).stream() .distinct() .map(tt -> new TestBean(tt.col + "_t")) // 新建对象,不修改原数据 .collect(Collectors.toList());
改完后的结果
调整后再跑代码,第一行输出就正常了:
[TestBean(col=aa_t), TestBean(col=bb_t)]
内容的提问来源于stack exchange,提问作者imlegend
相关产品推荐
相关产品推荐

