我有一个Person
类型的对象列表,并且我想使用流摆脱具有相同名称的元素。我在互联网上发现了使用 Wrapper类的建议,到目前为止,我的代码如下:
List<Person> people = Arrays.asList(new Person("Kowalski"),
new Person("Nowak"),
new Person("Big"),
new Person("Kowalski"));
List<Person> distPeople = people.stream()
.map(Wrapper::new)
.distinct()
.map(Wrapper::unwrap)
.collect(Collectors.toList());
在文档中,据说distinct()
返回由不同元素组成的流(根据 该流的Object.equals(Object))。
Wrapper
的实现无效(我有两个 Kowalski 获得相同的流):
public class Wrapper
{
private final Person person;
Wrapper(Person p)
{
person = p;
}
public Person unwrap()
{
return person;
}
public boolean equals(Object other)
{
if(other instanceof Wrapper)
return ((Wrapper) other).person.getName().equals(person.getName());
else
return false;
}
}
添加以下内容后,Wrapper
类的实现将生效:
@Override
public int hashCode()
{
return person.getName().hashCode();
}
有人可以解释为什么在hashCode()
类Wrapper
中重写distinct()
后起作用了吗?
答案 0 :(得分:2)
从等于Java文档开始
通常每当有必要重写hashCode方法时, 等于方法被重写,从而维护总合同 对于hashCode方法,该方法指出相等的对象必须具有 相等的哈希码。
请阅读有关合同here的详细信息
答案 1 :(得分:2)
答案在List
类中。方法DistinctOps
用于返回包含不同元素的makeRef
实例。此方法利用ReferencePipeline
执行LinkedHashSet
操作以获取不同的元素。请注意,reduce
是从LinkedHashSet
扩展而来的,其中HashSet
使用HashMap
存储元素。现在,为了使HashMap
正常工作,您应该提供hashCode()
的实现,该实现遵循hashCode()
和equals()
之间的正确约定,因此,需要提供hasCode()
的实现,以便Stream#distinct()
正常工作。
答案 2 :(得分:2)
distinct()
操作在内部使用HashSet
来检查它是否已经处理了某个元素。 HashSet
依次依赖其元素to sort them into buckets的hashCode()
方法。
如果不重写hashCode()
方法,它将退回到其默认值,并返回对象的身份,这通常在两个对象之间有所不同,即使根据equal()
它们是相同的。因此HashSet
将它们放入不同的存储桶中,无法再确定它们是“相同”对象。