Java编程系列Java8使用List的Stream收集转换成Set,数据却丢失了,你知道为啥吗?
Posted 善良勤劳勇敢而又聪明的老杨
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java编程系列Java8使用List的Stream收集转换成Set,数据却丢失了,你知道为啥吗?相关的知识,希望对你有一定的参考价值。
热门系列:
1、前言
前段时间,做业务时。一个列表数据,为了达到去重的效果。然后直接顺手,就用了List的stream流收集器,直接转成Set了。结果上线之后,出现了数据“莫名奇妙的”缺失情况。。。
于是开始了日志查看情况,最终将问题定位在了类似如下这段代码处:
List<Object> list = new ArrayList<>();
Set<Object> set = list.stream().collect(Collectors.toSet());
2、正文
因为,List集合中存储的是对象(Java中万物皆对象,所以这里可以理解成任何类型)。在做Set转换时,疏忽了Set底层的去重比较实现。。而HashSet底层正是使用了HashCode哈希算法来做比较的。所以,即使是多个内容不同的对象,都有可能会是相同的hash值,导致被认为是同一对象来处理!!(反之,2个相同内容的对象,hash值也不一定相等)
看下面这个例子:
static class Person {
String name;
int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\\'' +
", age=" + age +
'}';
}
}
public static void main(String[] args) {
Person p1=new Person("海绵宝宝",18);
Person p2=new Person("派大星",19);
Person p3=new Person("蟹老板",20);
Person p4=new Person("海绵宝宝",18);
Set<Person> p=new HashSet<Person>();
p.add(p1);
p.add(p2);
p.add(p3);
p.add(p4);
//先不重写Person的equals和hashCode方法,看下HashSet存储情况
for (Person ps:p) {
System.out.println(ps);
}
}
对于我们的业务处理来说,p1和p4这2个对象,按理应该需要做为同1个对象处理的。但是我们看下打印情况:
Person{name='海绵宝宝', age=18}
Person{name='派大星', age=19}
Person{name='海绵宝宝', age=18}
Person{name='蟹老板', age=20}
明显,p1和p4被当做了2个不同的对象,放进了Set中。所以,此时我们如果需要做去重处理,我们应该需要重写对象的equals()和hashCode()方法。
static class Person {
String name;
int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() { //打印时输出内容,否则输出地址
return "Person{" +
"name='" + name + '\\'' +
", age=" + age +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age &&
Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
再执行一下:
Person{name='海绵宝宝', age=18}
Person{name='蟹老板', age=20}
Person{name='派大星', age=19}
我们要的去重效果就达到咯!!!
所以,回归到本文的问题点上!!!导致数据丢失的情况,则正是因为没有重写equals()和hashCode()方法,导致可能有的数据有相同的Hash值,被去重处理掉了。
3、总结
吃一堑,长一智!以此记录,共勉!!!
以上是关于Java编程系列Java8使用List的Stream收集转换成Set,数据却丢失了,你知道为啥吗?的主要内容,如果未能解决你的问题,请参考以下文章
java8 stream, map, Option 等函数式编程的使用例子