我什么时候应该实施比较器?

When should I implement Comparator?

所以我正在学习 Comparator 和 Comparable,我遇到了以下问题。 我有一个 class:

public class PhoneBook implements Comparator<Name>{

    private SortedMap<Name, Integer> directory ;

    //class code constructor etc.

    //this is the method that the compiler wants if implementing Comparator
    @Override
    public int compare(Name o1, Name o2) {

        return o1.firstName.compareTo(o2.firstName);
      }
}

另一个class,Name实现了Comparable,构造函数中有first和last两个String。我不完全理解的是 Comparator 的功能,我已经阅读了 Java 文档并且我知道它用于对元素进行不同的排序而不更改名称 class 在我的示例中它也可以允许 null某些情况下的值,但我的 class 构造函数中的这个声明工作正常,我根本不需要在 PhoneBook class 中实现比较器接口:

Public PhoneBook(ArrayList<Name> names, ArrayList<Integer> phones) {
    this.directory = new TreeMap<Name, Integer>(new Comparator<Name>(){

        @Override
        public int compare(Name o1, Name o2) {

            return o1.firstName.compareTo(o2.firstName);
        }

     });
    //other constructor code to populate map
}

并且实现了我希望它实现的功能,而不需要PhoneBook实现Comparator接口class。我的问题是 class 什么时候想要实现 Comparator 接口?有没有一种不同的方法可以让地图使用不同的排序方法(与 class 名称中的 Comparable 接口提供的排序方法不同),而无需在初始化时将其传递给匿名 class?如果这个问题不够清楚,或者不适合这个网站,我很抱歉。

编辑:我理解 Comparable 与 Comparator 的争论以及何时使用它们。我的问题更多是关于如何使用比较器。您可以在初始化时对 Map 进行排序而不向其传递新的 Comparator 吗? class 什么时候实现这个接口是个好主意?

类 实现 Comparator 不应该做任何其他事情。

由于大多数这样的 classes 仅在一个地方使用,因此通常不命名地实现它们,即作为匿名 class 就像您在第二个示例中所做的那样。

但是,如果您希望 Comparator 可重复使用,最好为它创建一个独立的 class,例如在您的示例中将其命名为 FirstNameComparator

请注意,在 Java 8+ 中,使用 lambda 表达式比使用匿名 class 更容易(因为从逻辑上讲,lambda 表达式就是这样),以及方法参考用于可重复使用的比较。

// Using anonymous class (Java 1.2+)
this.directory = new TreeMap<Name, Integer>(new Comparator<Name>() {
    @Override
    public int compare(Name n1, Name n2) {
        return n1.getFirstName().compareTo(n2.getFirstName());
    }
});
// Reusable named class (Java 1.2+)
public final class FirstNameComparator implements Comparator<Name> {
    @Override
    public int compare(Name n1, Name n2) {
        return n1.getFirstName().compareTo(n2.getFirstName());
    }
}

// Then use it like this:
this.directory = new TreeMap<Name, Integer>(new FirstNameComparator());
// Using lambda expression (Java 8+)
this.directory = new TreeMap<Name, Integer>(
    (n1, n2) -> n1.getFirstName().compareTo(n2.getFirstName())
);
// Using method reference (Java 8+)
public class PhoneBook {
    public PhoneBook(ArrayList<Name> names, ArrayList<Integer> phones) {
        this.directory = new TreeMap<Name, Integer>(PhoneBook::compareFirstName);
        // other constructor code
    }
    private static int compareFirstName(Name n1, Name n2) { // public, if reusable
        return n1.getFirstName().compareTo(n2.getFirstName());
    }
    // other PhoneBook code
}
// Using Comparator helper (Java 8+)
this.directory = new TreeMap<Name, Integer>(Comparator.comparing(Name::getFirstName));