Java distinct()方法不为HashSet元素流返回不同的元素

Java distinct()方法不为HashSet元素流返回不同的元素,java,java-8,Java,Java 8,假设我有一个Employee类,它正确地重写了equals和hashcode方法 public class Employee { private int eno; private String firstName; private String lastName; @Override public int hashCode() { System.out.println("hashcode called"); final int prime = 31; int resu

假设我有一个Employee类,它正确地重写了equals和hashcode方法

public class Employee {

private int eno;
private String firstName;
private String lastName;

@Override
public int hashCode() {
    System.out.println("hashcode called");
    final int prime = 31;
    int result = 1;
    result = prime * result + eno;
    result = prime * result + ((firstName == null) ? 0 : firstName.hashCode());
    result = prime * result + ((lastName == null) ? 0 : lastName.hashCode());
    return result;
}

@Override
public boolean equals(Object obj) {
    System.out.println("equals called");
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (getClass() != obj.getClass())
        return false;
    Employee other = (Employee) obj;
    if (eno != other.eno)
        return false;
    if (firstName == null) {
        if (other.firstName != null)
            return false;
    } else if (!firstName.equals(other.firstName))
        return false;
    if (lastName == null) {
        if (other.lastName != null)
            return false;
    } else if (!lastName.equals(other.lastName))
        return false;
    return true;
}
}
测试等级如下

class Test {

    public static void main(String[] args) {

        Employee e1 = new Employee(1, "Karan", "Mehara");
        Employee e2 = new Employee(2, "Rajesh", "Shukla");

        Set<Employee> emps= new HashSet<>();
        emps.add(e1);
        emps.add(e2);
        System.out.println(emps);

        // No such requirement just for testing purpose modifying 
        e2.setEno(1);
        e2.setFirstName("Karan");
        e2.setLastName("Mehara");

        System.out.println(emps);

        emps.stream().distinct().forEach(System.out::println);
    }

}
类测试{
公共静态void main(字符串[]args){
员工e1=新员工(1,“卡兰”、“梅哈拉”);
雇员e2=新雇员(2,“Rajesh”、“Shukla”);
Set emps=new HashSet();
环境管理计划增补(e1);
emps.add(e2);
系统输出打印LN(emps);
//仅出于测试目的,没有此类要求
e2.塞特诺(1);
e2.setFirstName(“卡兰”);
e2.setLastName(“Mehara”);
系统输出打印LN(emps);
emps.stream().distinct().forEach(System.out::println);
}
}
上述程序的输出为:

[Employee[eno=1,firstName=Karan,lastName=Mehara],Employee[eno=2,firstName=Rajesh,lastName=Shukla]]

[Employee[eno=1,firstName=Karan,lastName=Mehara],Employee[eno=1,firstName=Karan,lastName=Mehara]]

员工[eno=1,firstName=Karan,lastName=Mehara]

员工[eno=1,firstName=Karan,lastName=Mehara]

为什么distinct()方法返回重复的元素

根据employee类的equals()和hashcode()方法,这两个对象是相同的

我已经注意到,当我调用distinct()方法equals()和hashcode()方法时,不会对集合实现流调用,而是对列表实现流调用

正如JavaDoc所说 distinct()返回一个由不同元素组成的流(根据该流的Object.equals(Object))

/**
     * Returns a stream consisting of the distinct elements (according to
     * {@link Object#equals(Object)}) of this stream.
     *
     * <p>For ordered streams, the selection of distinct elements is stable
     * (for duplicated elements, the element appearing first in the encounter
     * order is preserved.)  For unordered streams, no stability guarantees
     * are made.
     *
     * <p>This is a <a href="package-summary.html#StreamOps">stateful
     * intermediate operation</a>.
     *
     * @apiNote
     * Preserving stability for {@code distinct()} in parallel pipelines is
     * relatively expensive (requires that the operation act as a full barrier,
     * with substantial buffering overhead), and stability is often not needed.
     * Using an unordered stream source (such as {@link #generate(Supplier)})
     * or removing the ordering constraint with {@link #unordered()} may result
     * in significantly more efficient execution for {@code distinct()} in parallel
     * pipelines, if the semantics of your situation permit.  If consistency
     * with encounter order is required, and you are experiencing poor performance
     * or memory utilization with {@code distinct()} in parallel pipelines,
     * switching to sequential execution with {@link #sequential()} may improve
     * performance.
     *
     * @return the new stream
     */
    Stream<T> distinct();
/**
*返回由不同元素组成的流(根据
*此流的{@link Object#等于(Object)})。
*
*对于有序流,不同元素的选择是稳定的
*(对于重复的元素,元素在相遇中首先出现
*对于无序流,没有稳定性保证
*这是我们制造的。
*
*这是一个问题。
*
*@apiNote
*在并行管道中保持{@code distinct()}的稳定性是非常重要的
*相对昂贵(要求操作作为完全屏障,
*具有大量缓冲开销),通常不需要稳定性。
*使用无序流源(例如{@link#generate(Supplier)})
*或者删除带有{@link#unordered()}的排序约束可能会导致
*并行执行{@code distinct()}的效率要高得多
*管道,如果您的情况语义允许的话。如果一致性
*需要使用遭遇命令,并且您的性能不佳
*或并行管道中{@code distinct()}的内存利用率,
*使用{@link#sequential()}切换到顺序执行可能会有所改善
*表演。
*
*@返回新的流
*/
流独立();
A
集合
是“不包含重复元素的集合”。因此,
独特的
-集合方法很可能实现为什么都不做,因为它已经被认为值是唯一的

Javadoc中明确提到了您所做的工作:

注意:如果将可变对象用作集合元素,则必须非常小心。当对象是集合中的元素时,如果对象的值以影响相等比较的方式更改,则不会指定集合的行为。这种禁止的一种特殊情况是,不允许集合本身包含为元素


@MirkoAlicastro您可以比较原语(例如
int
,它是
eno
的类型),它不会按ref而按值进行比较。@MirkoAlicastro我给出的上述示例仅用于测试目的。我的问题是,如果我调用distinct()方法,为什么hashCode和equal方法不会调用。我读错了,我认为它们都是employee object,
System.out.println(e1.equals(e2))
return
true
就在
Stream
部分之前答案是您做了一个错误的操作:您正在编辑一个插入到hashmap中的对象。插入对象时,不应修改哈希代码使用的字段。您应该删除它,修改它,然后重新插入它,以便在hashmap中为它提供正确的位置