Java compareTo 方法失败

Java compareTo method fails

我有一个名为 class 的任务,我想将其放入 PriorityQueue。

我的 class 可与 日期 和一个名为 isUrgent

的布尔字段进行比较
 @Override
        public int compareTo(Task task) {
            int x = 0;
            if (!isUrgent && task.isUrgent)
                x=1;
            else if (isUrgent && !task.isUrgent)
                x=-1;
            else return  date.compareTo(task.date);

            return x +date.compareTo(task.date);
        }

第一次使用 Comparables,当我从优先级队列中删除一个任务时,它应该在最近的日期之前被删除,但如果它是紧急的,那么它应该被删除第一个紧急任务。

但是我在删除过程中得到了这个,

Task{isUrgent=true, date=Sat Apr 04 00:00:00 BST 2020}
Task{isUrgent=true, date=Sat Apr 04 00:00:00 BST 2020}
Task{isUrgent=false, date=Sat Apr 04 00:00:00 BST 2020}
Task{isUrgent=true, date=Thu Apr 04 00:00:00 BST 2030}
Task{isUrgent=false, date=Sat Apr 04 00:00:00 BST 2020}
Task{isUrgent=true, date=Thu Apr 04 00:00:00 BST 2030}
Task{isUrgent=false, date=Thu Apr 04 00:00:00 BST 2030}
Task{isUrgent=false, date=Thu Apr 04 00:00:00 BST 2030}

我在 compareTo 方法中做错了什么?

return x + date.compareTo(task.date) 你没有给你的 urgent 标志足够的权重。

如果x为-1,日期比较的结果为1,则return归零。

此外,不能保证日期比较会 return -1、0 或 1(即使初步测试指出确实如此)。 Javadoc 只是声明:

Returns:
the value 0 if the argument Date is equal to this Date; a value less than 0 if this Date is before the Date argument; and a value greater than 0 if this Date is after the Date argument.

一个简单的解决方法是:

@Override
public int compareTo(Task task) {
    if (!isUrgent && task.isUrgent)
        return 1;
    else if (isUrgent && !task.isUrgent)
        return -1;

    return date.compareTo(task.date);
}

您似乎想要的是先按紧急程度比较任务,然后再按日期进行比较。您不应将两个比较器的结果相加,而应将结果链接起来,以便仅在两个任务的紧急程度相同时才比较它们的日期(即,两者都是紧急的,或者都是非紧急的)。

幸运的是,Comparator class 有一些有用的方法,可以轻松创建一个满足您需要的比较器。大多数时候,包括在您的用例中,您不需要实际编写自己的 compareTo 方法。您可以使用 comparing method to compare by urgency or date, and you can use thenComparing to chain them together. The reversed 方法来比较紧急程度,以便 true 发生在 false 之前。

Comparator<Task> cmp =
    Comparator.comparing(t -> t.isUrgent).reversed().thenComparing(t -> t.date);

或者使用方法引用(如果你的 class 有 getter 方法):

Comparator<Task> cmp =
    Comparator.comparing(Task::isUrgent).reversed().thenComparing(Task::getDate);

然后您可以通过调用适当的 PriorityQueue constructor:

创建一个使用此比较器的优先级队列
PriorityQueue<Task> queue = new PriorityQueue<>(cmp);