Java 试图通过哈希集的构造函数传递比较器

Java 试图通过哈希集的构造函数传递比较器,java,lambda,comparator,Java,Lambda,Comparator,当我试图弄清楚如何正确使用比较器时,我正在尝试在哈希集中对我的员工排序。所以我这样做了: Set<Employee> EmployeeSet = new HashSet<Employee>((a,b)->a.getAge()-b.getAge()); 编辑: Queue<Employee> list = new PriorityQueue<>(Comparator.comparingInt(Employee::getAge)); 使用Pr

当我试图弄清楚如何正确使用
比较器时,我正在尝试在
哈希集中对我的
员工
排序。所以我这样做了:

Set<Employee> EmployeeSet = new HashSet<Employee>((a,b)->a.getAge()-b.getAge());
编辑

Queue<Employee> list = new PriorityQueue<>(Comparator.comparingInt(Employee::getAge));
使用PriorityQueue,它可以完美地工作:

Queue<Employee> list = new PriorityQueue<Employee>((a,b)->a.getAge()-b.getAge());
Queue list=newpriorityqueue((a,b)->a.getAge()-b.getAge());
为什么会这样?

您可以使用一个确保基于
比较器的有序
集合

Set<Employee> employeeSet = new TreeSet<>(Comparator.comparingInt(Employee::getAge));
// (a, b) -> a.getAge() - b.getAge() >>> Comparator.comparingInt(Employee::getAge

工作正常,因为它再次是一个有序集合,在其一个构造函数中接受一个
比较器

机械地说,
哈希集
不依赖
比较器
可比
接口来确定顺序或唯一性;相反,它依赖于放置在其中的单个元素的
hashCode

这就是为什么不能将其添加为构造函数参数;尝试将具有自然顺序的值插入到哈希映射中没有任何意义。除非集合的实现另有规定,否则集合在默认情况下是无序的
HashSet
是集合的无序实现


PriorityQueue
TreeMap
使用比较器和
compariable
元素的原因在于它们的结构方式。
PriorityQueue
TreeMap
order元素,因此在没有实现
compariable
的元素的情况下,使用
比较器来驱动它是可取的。这些数据结构是有序的,因此强制自定义排序是这些数据结构的一项功能。

正如其他人所指出的,
哈希集是无序集,因此它不能使用提供排序顺序的比较器。您可能需要使用排序集,例如
TreeSet

    Set<Employee> employeeSet = new TreeSet<>((a,b)->a.getAge()-b.getAge());
这确实会按年龄对员工进行分类。然而

    Employee terry = new Employee("Terry", 37);
    Employee kelly = new Employee("Kelly", 26);
    Employee brett = new Employee("Brett", 32);
    Employee chris = new Employee("Chris", 26);
    List<Employee> employeeList = Arrays.asList(terry, kelly, brett, chris);
    Set<Employee> employeeSet = new TreeSet<>(Comparator.comparingInt(Employee::getAge));
    employeeSet.addAll(employeeList);
    System.out.println(employeeSet);

    [Employee{name=Kelly, age=26}, Employee{name=Brett, age=32}, Employee{name=Terry, age=37}]
这怎么可能?提供的比较器不仅用于排序,还用于确定集合成员资格。由于凯利和克里斯年龄相同,这个比较者认为他们是平等的,所以他们中只有一人最终进入了这一组

您可能不想使用
TreeSet
按可能有重复项的值进行排序,因为这将导致项目丢失。你可以做几件事。第一,您可以将员工放入列表中,然后对列表进行排序:

    employeeList.sort(Comparator.comparingInt(Employee::getAge));

    // before
    [Employee{name=Terry, age=37}, Employee{name=Kelly, age=26}, Employee{name=Brett, age=32}, Employee{name=Chris, age=26}]

    // after
    [Employee{name=Kelly, age=26}, Employee{name=Chris, age=26}, Employee{name=Brett, age=32}, Employee{name=Terry, age=37}]
或者,您可以编写一个更复杂的比较器来区分输入数据的每个元素,这样就不会有两个元素被认为是重复的。在一个现实的例子中,员工可以有相同的名字,因此我们可能还希望包含一些真正独特的东西的比较,例如员工ID。然而,对于这个简单的例子,我们可以只根据员工的名字排序:

    Set<Employee> employeeSet = new TreeSet<>(Comparator.comparingInt(Employee::getAge)
                                                        .thenComparing(Employee::getName));

“…它会出错…”-这是什么意思?编译错误?运行时错误?顺序不对?请精确。@Turing85非常确定,如果使用相同的代码,编译错误非常明显。不过,这只是一个观点。@nullpointer是的,如果您了解javaapi的细节,这是显而易见的。但不是每个人都这样。此外,明确指出调试问题“必须包括[…]一个特定的问题[…]”。哈希集是无序集合。如果仍然感到奇怪,有序集合和无序集合是这里的关键区别。
    System.out.println(employeeSet.contains(kelly)); // true
    System.out.println(employeeSet.contains(chris)); // true
    employeeList.sort(Comparator.comparingInt(Employee::getAge));

    // before
    [Employee{name=Terry, age=37}, Employee{name=Kelly, age=26}, Employee{name=Brett, age=32}, Employee{name=Chris, age=26}]

    // after
    [Employee{name=Kelly, age=26}, Employee{name=Chris, age=26}, Employee{name=Brett, age=32}, Employee{name=Terry, age=37}]
    Set<Employee> employeeSet = new TreeSet<>(Comparator.comparingInt(Employee::getAge)
                                                        .thenComparing(Employee::getName));
    [Employee{name=Chris, age=26}, Employee{name=Kelly, age=26}, Employee{name=Brett, age=32}, Employee{name=Terry, age=37}]