You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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]

问题出在哪

  1. 自定义对象的equals/hashCode没写对:
    你的TestBean如果是非静态内部类,Lombok自动生成的equals和hashCode会带上外部类的实例引用,这就导致两个TestBean("bb")哪怕col一样,也会被判定成不同的对象,distinct()自然过滤不掉重复。
    另外,如果Lombok的注解没生效(比如依赖没加对、版本有问题),也会导致equals和hashCode不是基于col生成的,去重肯定失效。

  2. 对象修改的小陷阱(不是直接原因,但容易搞混):
    你在map里直接改了原对象的col属性,但distinct()是在map之前执行的,这个修改不会影响去重逻辑,只是会让保留下来的对象属性变了,但这不是去重失效的根因。

怎么解决

  1. 修正自定义类的相等性判断:

    • 如果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 + ")";
          }
      }
      
  2. 别改原对象,创建新对象:
    函数式编程尽量别搞副作用,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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 01:20:21