为什么compareTo使用比较器在用户分开时不执行NPE引发NPE

我创建了一个不会抛出NPE的比较器。但是,在compareTo中使用它时,它将引发NPE。为什么?

public class Person implements Comparable<Person> {
    public static final Comparator<Person> BIRTHDATE_ASCENDING_NULLS_FIRST = Comparator
            .nullsFirst(Comparator.comparing(Person::getBirthDate,Comparator.nullsFirst(Comparator.naturalOrder())));

    private String name;
    private LocalDate birthDate;

    public Person() {
        super();
    }

    public Person(String name,LocalDate birthDate) {
        this();
        this.name = name;
        this.birthDate = birthDate;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public LocalDate getBirthDate() {
        return birthDate;
    }

    public void setBirthDate(LocalDate birthDate) {
        this.birthDate = birthDate;
    }

    @Override
    public String toString() {
        return name + " was born on " + (birthDate == null ? "???" : birthDate);
    }

    @Override
    public int compareTo(Person other) {
        // BEGIN ADITIONAL TESTS
        if (other == null) {
            return 1;
        } else if (getBirthDate() == null ^ other.getBirthDate() == null) {
            // nulls first
            return getBirthDate() == null ? -1 : 1;
        } else if (getBirthDate() == null) {
            // both are null
            return 0;
        }
        System.out.println(this.toString() + "," + other.toString());
        // END ADITIONAL TESTS
        return BIRTHDATE_ASCENDING_NULLS_FIRST.compare(this,other);
    }

    @Override
    public int hashCode() {
        int result = 1;

        result = 31 * result + (birthDate == null ? System.identityHashCode(this) : birthDate.hashCode());

        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }

        if (obj == null || getclass() != obj.getclass()) {
            return false;
        }

        return Objects.equals(birthDate,((Person) obj).getBirthDate());
    }

    public static void main(String[] args) {
        List<Person> people = new ArrayList<>();
        people.add(null);
        people.add(new Person("John",null));
        people.add(new Person("Mary",LocalDate.now().minusYears(20)));
        people.add(new Person("George",LocalDate.now().minusYears(10)));

        Collections.sort(people,BIRTHDATE_ASCENDING_NULLS_FIRST);
        System.out.println(people);

        Collections.sort(people);
        System.out.println(people);

        Collections.sort(people,BIRTHDATE_ASCENDING_NULLS_FIRST.reversed());
        System.out.println(people);

        // This one throws NPE
        Collections.sort(people);
        System.out.println(people);
    }

Collections.sort调用中显露比较器时,排序操作未按预期使用compareTo实现。
不执行此操作时,排序操作将使用compareTo的实现。由于此方法调用的是完全相同的比较器,为什么在这里得到NPE?我的意思是,为什么从compareTo调用比较器时,它不处理NPE?

iCMS 回答:为什么compareTo使用比较器在用户分开时不执行NPE引发NPE

sort的其他调用不会引发NPE,因为它们会调用Comparator.compare。该呼叫可能看起来像这样:

theComparatorYouPassedToSort.compare(item1,item2)

一个实际示例位于TimSort.java第355行:

if (c.compare(a[runHi++],a[lo]) < 0) {

但是,不占用sort(抛出NPE的那个)的Comparator重载会调用Person.compareTo。呼叫看起来像:

item1.compareTo(item2)

一个实际示例位于ComparableTimSort.java第321行:

while (runHi < hi && ((Comparable) a[runHi]).compareTo(a[runHi - 1]) < 0)

现在,无论处理compareTo的内部逻辑的null是什么,如果item1为null,则以上内容将引发NPE。如果compareTo的参数为null,则您实施item2只会阻止NPE。它可以处理null参数,但是不能更改调用Person.compare的方式。如果在空对象上调用它,则仍会引发NPE。

本文链接:https://www.f2er.com/1930930.html

大家都在问