我什么时候应该使用比较器与可比的?

发布于 2025-01-27 09:34:09 字数 1750 浏览 2 评论 0 原文

我有一个需要以某种方式进行分类的pojos列表。我在POJO类中定义了 comprator 并使用它来对列表进行排序。

以下方式正确/最佳实践吗?有更好的方法吗?

    public class CompratorTest {

    public static void main(String[] args) {

        List<Person> people = List.of(
                new Person("zoe", "saturday", 40),
                new Person("luca", "red", 15),
                new Person("boris", "vin", 54),
                new Person("boris", "apple", 33),
                new Person("boris", "apple", 70)
        );

        List<Person> sortedPeople =
                people.stream()
                        .sorted((person, other) -> Person.COMPARATOR.compare(person, other))
                        .collect(Collectors.toList());

        sortedPeople.forEach(System.out::println);
    }

    @Data
    @AllArgsConstructor
    static
    class Person {
        final static Comparator<Person> COMPARATOR =
                Comparator.comparing((Person person) -> person.getName())
                        .thenComparing(person -> person.getSurname())
                        .thenComparing(person -> person.getAge());

        String name;
        String surname;
        int age;
    }
}

顺便说一句,输出是正确的。

编辑 添加更经典的方式:

    @Data
    @AllArgsConstructor
    static class Animal implements Comparable<Animal> {

        String name;
        String race;

        @Override
        public int compareTo(Animal other) {
            if (this.name.equals(other.name)) {
                return String.CASE_INSENSITIVE_ORDER.compare(this.race, other.race);
            }

            return String.CASE_INSENSITIVE_ORDER.compare(this.name, other.name);
        }
    }

您认为哪一种是更好的解决方案?

I have a list of POJOs I need to sort somehow. I define a Comprator inside the POJO class and use it to sort the list.

Is the following way correct/best practice? Is there a better way to do it?

    public class CompratorTest {

    public static void main(String[] args) {

        List<Person> people = List.of(
                new Person("zoe", "saturday", 40),
                new Person("luca", "red", 15),
                new Person("boris", "vin", 54),
                new Person("boris", "apple", 33),
                new Person("boris", "apple", 70)
        );

        List<Person> sortedPeople =
                people.stream()
                        .sorted((person, other) -> Person.COMPARATOR.compare(person, other))
                        .collect(Collectors.toList());

        sortedPeople.forEach(System.out::println);
    }

    @Data
    @AllArgsConstructor
    static
    class Person {
        final static Comparator<Person> COMPARATOR =
                Comparator.comparing((Person person) -> person.getName())
                        .thenComparing(person -> person.getSurname())
                        .thenComparing(person -> person.getAge());

        String name;
        String surname;
        int age;
    }
}

Output is correct, by the way.

EDIT
Adding a more classic way:

    @Data
    @AllArgsConstructor
    static class Animal implements Comparable<Animal> {

        String name;
        String race;

        @Override
        public int compareTo(Animal other) {
            if (this.name.equals(other.name)) {
                return String.CASE_INSENSITIVE_ORDER.compare(this.race, other.race);
            }

            return String.CASE_INSENSITIVE_ORDER.compare(this.name, other.name);
        }
    }

Which one do you think is a better solution?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

守不住的情 2025-02-03 09:34:09

比较器可比性之间的用例之间有一个很大的区别。

实现可比接口适用于在域模型中具有自然顺序的对象。我不确定动物是否具有自然秩序,但是从您的应用程序如何建模动物的角度来看,这是可以的。否则,您的班级不应实现可比性

这不是基于意见的东西,文档清楚地定义了何时使用这些接口。

此接口对每个类的对象施加了总订单
这实现了它。此顺序称为班级
自然订购
,以及类的 compareTo 方法称为
它的自然比较方法。

比较器还可以用于控制某些数据结构的顺序(例如排序集或排序地图),或者提供订购,用于集合没有的对象自然排序

另一个明显的区别,您可以根据需要定义比较器的多种口味。当没有一种特定方法比较和分类对象时,这很方便。而且它们必须比比较器具有更有意义的名称。

就您个人而言,我认为将几个比较器定义为公共静态最终字段,这并没有造成巨大伤害。如果您有一个类型的实例的单个类 - 将比较器提取到该类中,否则如果这些对象无处不在并且在许多地方使用,则可以将它们放在POJO内部(基于意见的部分)。

There's a substantial distinction between the use cases for Comparator and Comparable.

Implementing the Comparable interface is suitable for objects that have a natural order in your domain model. I'm not sure whether animals have a natural order, but if it is the case from the perspective of how your application model the animals, that's fine - that's the way to go. Otherwise, your class should not implement Comparable.

It's not something opinion-based, documentation clearly defines when these interfaces are intended to be used.

Comparable:

This interface imposes a total ordering on the objects of each class
that implements it. This ordering is referred to as the class's
natural ordering
, and the class's compareTo method is referred to as
its natural comparison method.

Comparator:

Comparators can also be used to control the order of certain data structures (such as sorted sets or sorted maps), or to provide an ordering for collections of objects that don't have a natural ordering.

Another obvious distinction, that you can define as many flavors of comparators as you need. Which is handy when there's no one specific way to compare and sort the objects. And they must have more meaningful names than comparator.

Personally, I don't see a huge harm in defining a couple of comparators as public static final fields, as in your example. If you have a single class that manages the instances of this type - extract the comparators into that class, otherwise if these objects are ubiquitous and used in many places you can leave them right inside the POJO (that an opinion based part).

百思不得你姐 2025-02-03 09:34:09

这不是基于意见的:tl; dr Imparace <代码>可比:

  • 语义上,这是界面设计的目的:它们表达由对象执行的合同,对象的行为:如果对象可以序列化,然后他们应该实现序列化,如果它们是可比的,则应实现可比等...

  • 继承将按预期工作,并且更可读性:如果定义了扩展 Animal dog >您可以使用超级实现(即像任何其他 Animal >)或覆盖实施以实施特定于> 的行为的 dog 。狗。您的 dog 类的用户简单地调用 instance.compareto(...),而不必担心她/他应该致电

    的最终静态比较器

  • 用户的 最终静态比较器动物 API知道他们必须在将自己的动物添加到继承树

    时必须实现可比性

This is not opinion based: TL;DR implement Comparable:

  • semantically, this is what Interfaces are designed for: they express a contract enforced by an object, a behavior of the object: if the objects are serializable, then they should implement Serializable, if they are comparable, then they should implement Comparable, etc...

  • inheritance will work as expected and be more readable: if you define a Dog that extends Animal, you can implement comparison for Dog using the super implementation (i.e. a Dog is compared like any other Animal) or overriding the implementation to implement a behavior specific to Dog. The user of your Dog class simply calls instance.compareTo(...) without having to worry about what final static comparator she/he should call

  • users of your Animal API know they have to implement Comparable when adding their own animal to the inheritance tree

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文