【问题标题】:How to compare objects by multiple fields如何按多个字段比较对象
【发布时间】:2010-09-27 00:55:19
【问题描述】:

假设您有一些对象有几个字段可以通过以下方式进行比较:

public class Person {

    private String firstName;
    private String lastName;
    private String age;

    /* Constructors */

    /* Methods */

}

所以在这个例子中,当你问是否:

a.compareTo(b) > 0

您可能会问 a 的姓是否在 b 之前,或者 a 是否比 b 大,等等...

在不增加不必要的混乱或开销的情况下,在这些类型的对象之间进行多重比较的最简洁的方法是什么?

  • java.lang.Comparable 接口只允许按一个字段进行比较
  • 在我看来,添加大量比较方法(即compareByFirstName()compareByAge() 等...)很混乱。

那么最好的方法是什么?

【问题讨论】:

标签: java oop


【解决方案1】:

使用 Java 8:

Comparator.comparing((Person p)->p.firstName)
          .thenComparing(p->p.lastName)
          .thenComparingInt(p->p.age);

如果你有访问器方法:

Comparator.comparing(Person::getFirstName)
          .thenComparing(Person::getLastName)
          .thenComparingInt(Person::getAge);

如果一个类实现了 Comparable,那么这样的比较器可以用在 compareTo 方法中:

@Override
public int compareTo(Person o){
    return Comparator.comparing(Person::getFirstName)
              .thenComparing(Person::getLastName)
              .thenComparingInt(Person::getAge)
              .compare(this, o);
}

【讨论】:

  • 特别是演员 (Person p) 对于链式比较器很重要。
  • 比较大量对象时的效率如何,例如排序的时候?是否必须在每次调用中创建新的 Comparator 实例?
  • 当我比较的字段之一为空(如字符串)时,我收到 NullPointerException。无论如何要保持这种比较格式,但允许它为空安全?
  • @jjurm .thenComparing(Person::getLastName, Comparator.nullsFirst(Comparator.naturalOrder())) - 第一个字段选择器,然后是比较器
  • @jjurm 当您在compareTo 中使用它时,如上所示,每次调用该方法时都会创建Comparator。您可以通过将比较器存储在私有静态最终字段中来防止这种情况。
【解决方案2】:

你应该实现Comparable <Person>。假设所有字段都不为null(为简单起见),即age为int,比较排名为first、last、age,compareTo方法就很简单了:

public int compareTo(Person other) {
    int i = firstName.compareTo(other.firstName);
    if (i != 0) return i;

    i = lastName.compareTo(other.lastName);
    if (i != 0) return i;

    return Integer.compare(age, other.age);
}

【讨论】:

  • 如果你实现 Comparable 那么方法是 compareTo(Person p).. 看来这个答案与 Comparator 的 compare 方法混淆了
  • 不建议这样做。当您有多个字段时使用 Comparator。
  • 这是目前最好的解决方案,(比更多的比较器更好)
  • @indika,我很好奇:为什么不推荐这样做?比较使用多个属性对我来说似乎非常好。
  • @ars-longa-vita-brevis,如果您使用 Comparable,那么排序逻辑必须在其对象被排序的同一类中,因此这称为对象的自然排序。通过使用 Comparator,您可以在 Person 类之外编写自定义排序逻辑。如果您只想按名字或姓氏比较 Person 对象,则不能使用此逻辑。你得再写一遍,
【解决方案3】:

(来自Ways to sort lists of objects in Java based on multiple fields

this gist中的工作代码

使用 Java 8 lambda(2019 年 4 月 10 日添加)

Java 8 通过 lambda 很好地解决了这个问题(尽管 Guava 和 Apache Commons 可能仍然提供更大的灵活性):

Collections.sort(reportList, Comparator.comparing(Report::getReportKey)
            .thenComparing(Report::getStudentNumber)
            .thenComparing(Report::getSchool));

感谢@gaaogong的answer below

凌乱而复杂:手工排序

Collections.sort(pizzas, new Comparator<Pizza>() {  
    @Override  
    public int compare(Pizza p1, Pizza p2) {  
        int sizeCmp = p1.size.compareTo(p2.size);  
        if (sizeCmp != 0) {  
            return sizeCmp;  
        }  
        int nrOfToppingsCmp = p1.nrOfToppings.compareTo(p2.nrOfToppings);  
        if (nrOfToppingsCmp != 0) {  
            return nrOfToppingsCmp;  
        }  
        return p1.name.compareTo(p2.name);  
    }  
});  

这需要大量输入、维护并且容易出错。

反射方式:使用 BeanComparator 排序

ComparatorChain chain = new ComparatorChain(Arrays.asList(
   new BeanComparator("size"), 
   new BeanComparator("nrOfToppings"), 
   new BeanComparator("name")));

Collections.sort(pizzas, chain);  

显然这更简洁,但更容易出错,因为您使用字符串代替了对字段的直接引用(没有类型安全,自动重构)。现在,如果一个字段被重命名,编译器甚至不会报告问题。而且,因为这个方案使用了反射,所以排序要慢很多。

到达那里:使用 Google Guava 的比较链进行排序

Collections.sort(pizzas, new Comparator<Pizza>() {  
    @Override  
    public int compare(Pizza p1, Pizza p2) {  
        return ComparisonChain.start().compare(p1.size, p2.size).compare(p1.nrOfToppings, p2.nrOfToppings).compare(p1.name, p2.name).result();  
        // or in case the fields can be null:  
        /* 
        return ComparisonChain.start() 
           .compare(p1.size, p2.size, Ordering.natural().nullsLast()) 
           .compare(p1.nrOfToppings, p2.nrOfToppings, Ordering.natural().nullsLast()) 
           .compare(p1.name, p2.name, Ordering.natural().nullsLast()) 
           .result(); 
        */  
    }  
});  

这要好得多,但对于最常见的用例需要一些样板代码:默认情况下,null-values 的值应该较小。对于空字段,您必须为 Guava 在这种情况下做什么提供额外的指令。如果您想做一些特定的事情,这是一种灵活的机制,但通常您需要默认情况(即 1、a、b、z、null)。

使用 Apache Commons CompareToBuilder 进行排序

Collections.sort(pizzas, new Comparator<Pizza>() {  
    @Override  
    public int compare(Pizza p1, Pizza p2) {  
        return new CompareToBuilder().append(p1.size, p2.size).append(p1.nrOfToppings, p2.nrOfToppings).append(p1.name, p2.name).toComparison();  
    }  
});  

与 Guava 的 ComparisonChain 一样,这个库类可以轻松地对多个字段进行排序,而且还定义了 null 值的默认行为(即 1、a、b、z、null)。但是,您也不能指定任何其他内容,除非您提供自己的 Comparator。

因此

最终归结为风味和灵活性需求(Guava 的 ComparisonChain)与简洁的代码(Apache 的 CompareToBuilder)。

奖励方式

我找到了一个很好的解决方案,它在 MultiComparator 中按优先级顺序组合了多个比较器 on CodeReview

class MultiComparator<T> implements Comparator<T> {
    private final List<Comparator<T>> comparators;

    public MultiComparator(List<Comparator<? super T>> comparators) {
        this.comparators = comparators;
    }

    public MultiComparator(Comparator<? super T>... comparators) {
        this(Arrays.asList(comparators));
    }

    public int compare(T o1, T o2) {
        for (Comparator<T> c : comparators) {
            int result = c.compare(o1, o2);
            if (result != 0) {
                return result;
            }
        }
        return 0;
    }

    public static <T> void sort(List<T> list, Comparator<? super T>... comparators) {
        Collections.sort(list, new MultiComparator<T>(comparators));
    }
}

当然,Apache Commons Collections 已经为此提供了一个实用工具:

ComparatorUtils.chainedComparator(comparatorCollection)

Collections.sort(list, ComparatorUtils.chainedComparator(comparators));

【讨论】:

    【解决方案4】:

    您可以实现一个Comparator,它比较两个Person 对象,并且您可以检查任意数量的字段。您可以在比较器中放入一个变量,告诉它要与哪个字段进行比较,尽管编写多个比较器可能会更简单。

    【讨论】:

    • 我实际上更喜欢使用单个比较器的想法。我不认为这个答案是错误的,但是任何阅读它的人都应该在下面查看 Steve Kuo 的答案。
    • 只有当您想要不同的比较方法而不是数据本身的功能时才使用多个比较器 - 即有时您想按名称比较,其他时候按年龄等。按多个字段进行比较同时,只需要一个比较器。
    【解决方案5】:

    @Patrick 要连续排序多个字段,请尝试ComparatorChain

    ComparatorChain 是一个 Comparator,它依次包装了一个或多个 Comparator。 ComparatorChain 按顺序调用每个 Comparator 直到 1) 任何单个 Comparator 返回非零结果(然后返回该结果),或 2) ComparatorChain 用尽(并返回零)。这种类型的排序与 SQL 中的多列排序非常相似,并且该类允许 Java 类在对 List 进行排序时模拟这种行为。

    为了进一步促进类似 SQL 的排序,列表中任何单个 Comparator 的顺序都可以>颠倒。

    在调用 compare(Object, Object) 之后调用添加新比较器或更改升序/降序排序的方法将导致 UnsupportedOperationException。但是,请注意不要更改底层的比较器列表或定义排序顺序的位集。

    ComparatorChain 的实例不同步。该类在构造时不是线程安全的,但在所有设置操作完成后执行多重比较是线程安全的。

    【讨论】:

      【解决方案6】:

      您始终可以考虑的另一个选项是 Apache Commons。它提供了很多选择。

      import org.apache.commons.lang3.builder.CompareToBuilder;
      

      例如:

      public int compare(Person a, Person b){
      
         return new CompareToBuilder()
           .append(a.getName(), b.getName())
           .append(a.getAddress(), b.getAddress())
           .toComparison();
      }
      

      【讨论】:

        【解决方案7】:

        您还可以查看实现 Comparator 的 Enum。

        http://tobega.blogspot.com/2008/05/beautiful-enums.html

        例如

        Collections.sort(myChildren, Child.Order.ByAge.descending());
        

        【讨论】:

          【解决方案8】:
          import com.google.common.collect.ComparisonChain;
          
          /**
           * @author radler
           * Class Description ...
           */
          public class Attribute implements Comparable<Attribute> {
          
              private String type;
              private String value;
          
              public String getType() { return type; }
              public void setType(String type) { this.type = type; }
          
              public String getValue() { return value; }
              public void setValue(String value) { this.value = value; }
          
              @Override
              public String toString() {
                  return "Attribute [type=" + type + ", value=" + value + "]";
              }
          
              @Override
              public int compareTo(Attribute that) {
                  return ComparisonChain.start()
                      .compare(this.type, that.type)
                      .compare(this.value, that.value)
                      .result();
              }
          
          }
          

          【讨论】:

          • 我非常喜欢这个策略。谢谢!
          • 最有效的方法!谢谢
          【解决方案9】:

          对于那些能够使用 Java 8 流式 API 的人,这里有一个更简洁的方法,有详细的文档记录: Lambdas and sorting

          我正在寻找 C# LINQ 的等效项:

          .ThenBy(...)
          

          我在 Comparator 上找到了 Java 8 中的机制:

          .thenComparing(...)
          

          所以这里是演示算法的 sn-p。

              Comparator<Person> comparator = Comparator.comparing(person -> person.name);
              comparator = comparator.thenComparing(Comparator.comparing(person -> person.age));
          

          查看上面的链接以了解更简洁的方式以及关于 Java 的类型推断如何使其与 LINQ 相比更笨拙的定义。

          这是完整的单元测试供参考:

          @Test
          public void testChainedSorting()
          {
              // Create the collection of people:
              ArrayList<Person> people = new ArrayList<>();
              people.add(new Person("Dan", 4));
              people.add(new Person("Andi", 2));
              people.add(new Person("Bob", 42));
              people.add(new Person("Debby", 3));
              people.add(new Person("Bob", 72));
              people.add(new Person("Barry", 20));
              people.add(new Person("Cathy", 40));
              people.add(new Person("Bob", 40));
              people.add(new Person("Barry", 50));
          
              // Define chained comparators:
              // Great article explaining this and how to make it even neater:
              // http://blog.jooq.org/2014/01/31/java-8-friday-goodies-lambdas-and-sorting/
              Comparator<Person> comparator = Comparator.comparing(person -> person.name);
              comparator = comparator.thenComparing(Comparator.comparing(person -> person.age));
          
              // Sort the stream:
              Stream<Person> personStream = people.stream().sorted(comparator);
          
              // Make sure that the output is as expected:
              List<Person> sortedPeople = personStream.collect(Collectors.toList());
              Assert.assertEquals("Andi",  sortedPeople.get(0).name); Assert.assertEquals(2,  sortedPeople.get(0).age);
              Assert.assertEquals("Barry", sortedPeople.get(1).name); Assert.assertEquals(20, sortedPeople.get(1).age);
              Assert.assertEquals("Barry", sortedPeople.get(2).name); Assert.assertEquals(50, sortedPeople.get(2).age);
              Assert.assertEquals("Bob",   sortedPeople.get(3).name); Assert.assertEquals(40, sortedPeople.get(3).age);
              Assert.assertEquals("Bob",   sortedPeople.get(4).name); Assert.assertEquals(42, sortedPeople.get(4).age);
              Assert.assertEquals("Bob",   sortedPeople.get(5).name); Assert.assertEquals(72, sortedPeople.get(5).age);
              Assert.assertEquals("Cathy", sortedPeople.get(6).name); Assert.assertEquals(40, sortedPeople.get(6).age);
              Assert.assertEquals("Dan",   sortedPeople.get(7).name); Assert.assertEquals(4,  sortedPeople.get(7).age);
              Assert.assertEquals("Debby", sortedPeople.get(8).name); Assert.assertEquals(3,  sortedPeople.get(8).age);
              // Andi     : 2
              // Barry    : 20
              // Barry    : 50
              // Bob      : 40
              // Bob      : 42
              // Bob      : 72
              // Cathy    : 40
              // Dan      : 4
              // Debby    : 3
          }
          
          /**
           * A person in our system.
           */
          public static class Person
          {
              /**
               * Creates a new person.
               * @param name The name of the person.
               * @param age The age of the person.
               */
              public Person(String name, int age)
              {
                  this.age = age;
                  this.name = name;
              }
          
              /**
               * The name of the person.
               */
              public String name;
          
              /**
               * The age of the person.
               */
              public int age;
          
              @Override
              public String toString()
              {
                  if (name == null) return super.toString();
                  else return String.format("%s : %d", this.name, this.age);
              }
          }
          

          【讨论】:

            【解决方案10】:

            为这样的用例手动编写Comparator 是一个糟糕的解决方案 IMO。这种临时方法有很多缺点:

            • 没有代码重用。违反 DRY。
            • 样板。
            • 增加出错的可能性。

            那么解决办法是什么?

            首先是一些理论。

            让我们用Ord A 表示“类型A 支持比较”的命题。 (从程序的角度来看,您可以将Ord A 视为一个对象,其中包含用于比较两个As 的逻辑。是的,就像Comparator。)

            现在,如果Ord AOrd B,那么它们的复合(A, B) 也应该支持比较。即Ord (A, B)。如果Ord AOrd BOrd C,则Ord (A, B, C)

            我们可以将此论点扩展到任意数量,并说:

            Ord A, Ord B, Ord C, ..., Ord ZOrd (A, B, C, .., Z)

            我们称这个语句为 1。

            复合材料的比较将按照您在问题中的描述进行:将首先尝试第一个比较,然后是下一个,然后是下一个,依此类推。

            这是我们解决方案的第一部分。现在是第二部分。

            如果您知道Ord A,并且知道如何将B 转换为A(调用该转换函数f),那么您也可以拥有Ord B。如何?那么,当要比较两个B 实例时,首先使用f 将它们转换为A,然后应用Ord A

            在这里,我们将转换B → A 映射到Ord A → Ord B。这称为逆变映射(或简称comap)。

            Ord A, (B → A)comapOrd B

            我们称这个语句为 2。


            现在让我们将此应用于您的示例。

            您有一个名为Person 的数据类型,它包含三个String 类型的字段。

            • 我们知道Ord String。根据声明 1,Ord (String, String, String)

            • 我们可以轻松地编写一个从Person(String, String, String) 的函数。 (只需返回三个字段。)由于我们知道Ord (String, String, String)Person → (String, String, String),通过语句2,我们可以使用comap 得到Ord Person

            QED。


            如何实现所有这些概念?

            好消息是您不必这样做。已经存在a library,它实现了本文中描述的所有想法。 (如果你好奇这些是如何实现的,可以look under the hood。)

            这是代码的外观:

            Ord<Person> personOrd = 
             p3Ord(stringOrd, stringOrd, stringOrd).comap(
               new F<Person, P3<String, String, String>>() {
                 public P3<String, String, String> f(Person x) {
                   return p(x.getFirstName(), x.getLastname(), x.getAge());
                 }
               }
             );
            

            说明:

            • stringOrdOrd&lt;String&gt; 类型的对象。这对应于我们最初的“支持比较”命题。
            • p3Ord 是一个接受Ord&lt;A&gt;Ord&lt;B&gt;Ord&lt;C&gt; 并返回Ord&lt;P3&lt;A, B, C&gt;&gt; 的方法。这对应于语句 1。(P3 代表具有三个元素的乘积。乘积是复合材料的代数项。)
            • comap 对应很好,comap
            • F&lt;A, B&gt; 表示转换函数A → B
            • p 是创建产品的工厂方法。
            • 整个表达式对应语句 2。

            希望对您有所帮助。

            【讨论】:

              【解决方案11】:

              您可能只想在 Person 类中定义几种类型的“Comparator”子类,而不是比较方法。这样您就可以将它们传递给标准的 Collections 排序方法。

              【讨论】:

                【解决方案12】:
                //Following is the example in jdk 1.8
                package com;
                import java.util.ArrayList;
                import java.util.Comparator;
                import java.util.List;
                
                class User {
                    private String firstName;
                    private String lastName;
                    private Integer age;
                
                    public Integer getAge() {
                        return age;
                    }
                
                    public User setAge(Integer age) {
                        this.age = age;
                        return this;
                    }
                
                    public String getFirstName() {
                        return firstName;
                    }
                
                    public User setFirstName(String firstName) {
                        this.firstName = firstName;
                        return this;
                    }
                
                    public String getLastName() {
                        return lastName;
                    }
                
                    public User setLastName(String lastName) {
                        this.lastName = lastName;
                        return this;
                    }
                
                }
                
                public class MultiFieldsComparision {
                
                    public static void main(String[] args) {
                        List<User> users = new ArrayList<User>();
                
                        User u1 = new User().setFirstName("Pawan").setLastName("Singh").setAge(38);
                        User u2 = new User().setFirstName("Pawan").setLastName("Payal").setAge(37);
                        User u3 = new User().setFirstName("Anuj").setLastName("Kumar").setAge(60);
                        User u4 = new User().setFirstName("Anuj").setLastName("Kumar").setAge(43);
                        User u5 = new User().setFirstName("Pawan").setLastName("Chamoli").setAge(44);
                        User u6 = new User().setFirstName("Pawan").setLastName("Singh").setAge(5);
                
                        users.add(u1);
                        users.add(u2);
                        users.add(u3);
                        users.add(u4);
                        users.add(u5);
                        users.add(u6);
                
                        System.out.println("****** Before Sorting ******");
                
                        users.forEach(user -> {
                            System.out.println(user.getFirstName() + " , " + user.getLastName() + " , " + user.getAge());
                        });
                
                        System.out.println("****** Aftre Sorting ******");
                
                        users.sort(
                                Comparator.comparing(User::getFirstName).thenComparing(User::getLastName).thenComparing(User::getAge));
                
                        users.forEach(user -> {
                            System.out.println(user.getFirstName() + " , " + user.getLastName() + " , " + user.getAge());
                        });
                
                    }
                
                }
                

                【讨论】:

                  【解决方案13】:

                  如果您的比较算法“聪明”,我认为会更加混乱。我会采用您建议的众多比较方法。

                  对我来说唯一的例外是平等。对于单元测试,覆盖 .Equals(在 .net 中)以确定两个对象之间的多个字段是否相等(而不是引用相等)对我很有用。

                  【讨论】:

                    【解决方案14】:

                    如果用户可以通过多种方式订购人员,您还可以在某处将多个Comparators 设置为常量。大多数排序操作和排序集合都将比较器作为参数。

                    【讨论】:

                      【解决方案15】:

                      如果我们必须根据多个字段对 Person 对象进行排序,则此处是相同的代码实现。

                      import java.util.ArrayList;
                      import java.util.Collections;
                      import java.util.Comparator;
                      
                      public class Person {
                      
                      private String firstName;
                      private String lastName;
                      private int age;
                      
                      public String getFirstName() {
                          return firstName;
                      }
                      
                      public void setFirstName(String firstName) {
                          this.firstName = firstName;
                      }
                      
                      public String getLastName() {
                          return lastName;
                      }
                      
                      public void setLastName(String lastName) {
                          this.lastName = lastName;
                      }
                      
                      public int getAge() {
                          return age;
                      }
                      
                      public void setAge(int age) {
                          this.age = age;
                      }
                      
                      public Person(String firstName, String lastName, int age) {
                          this.firstName = firstName;
                          this.lastName = lastName;
                          this.age = age;
                      }
                      
                      
                      static class PersonSortingComparator implements Comparator<Person> {
                      
                          @Override
                          public int compare(Person person1, Person person2) {
                      
                              // for first name comparison
                              int firstNameCompare = person1.getFirstName().compareTo(person2.getFirstName());
                      
                              // for last name comparison
                              int lastNameCompare = person1.getLastName().compareTo(person2.getLastName());
                      
                              // for last name comparison
                              int ageCompare = person1.getAge() - person2.getAge();
                      
                              // Now comparing
                              if (firstNameCompare == 0) {
                                  if (lastNameCompare == 0) {
                                      return ageCompare;
                                  }
                                  return lastNameCompare;
                              }
                              return firstNameCompare;
                          }
                      }
                      
                      public static void main(String[] args) {
                          Person person1 = new Person("Ajay", "Kumar", 27);
                          Person person2 = new Person("Ajay","Gupta", 23);
                          Person person3 = new Person("Ajay","Kumar", 22);
                      
                      
                          ArrayList<Person> persons = new ArrayList<>();
                          persons.add(person1);
                          persons.add(person2);
                          persons.add(person3);
                      
                      
                          System.out.println("Before Sorting:\n");
                          for (Person person : persons) {
                              System.out.println(person.firstName + " " + person.lastName + " " + person.age);
                          }
                      
                          Collections.sort(persons, new PersonSortingComparator());
                      
                          System.out.println("After Sorting:\n");
                          for (Person person : persons) {
                              System.out.println(person.firstName + " " + person.lastName + " " + person.age);
                          }
                      }
                      
                      }
                      

                      【讨论】:

                        【解决方案16】:
                        //here threshold,buyRange,targetPercentage are three keys on that i have sorted my arraylist 
                        final Comparator<BasicDBObject> 
                        
                            sortOrder = new Comparator<BasicDBObject>() {
                                            public int compare(BasicDBObject e1, BasicDBObject e2) {
                                                int threshold = new Double(e1.getDouble("threshold"))
                                                .compareTo(new Double(e2.getDouble("threshold")));
                                                if (threshold != 0)
                                                    return threshold;
                        
                                                int buyRange = new Double(e1.getDouble("buyRange"))
                                                .compareTo(new Double(e2.getDouble("buyRange")));
                                                if (buyRange != 0)
                                                    return buyRange;
                        
                                                return (new Double(e1.getDouble("targetPercentage")) < new Double(
                                                        e2.getDouble("targetPercentage")) ? -1 : (new Double(
                                                                e1.getDouble("targetPercentage")) == new Double(
                                                                        e2.getDouble("targetPercentage")) ? 0 : 1));
                                            }
                                        };
                                        Collections.sort(objectList, sortOrder);
                        

                        【讨论】:

                        • 我来这个问题是因为我的代码开始喜欢你的回答;)
                        【解决方案17】:

                        迟到总比没有好 - 如果您正在寻找不必要的混乱或开销,那么在最少代码/快速执行方面很难击败以下内容。

                        数据类:

                        public class MyData {
                            int id;
                            boolean relevant;
                            String name;
                            float value;
                        }
                        

                        比较器:

                        public class MultiFieldComparator implements Comparator<MyData> {
                            @Override
                            public int compare(MyData dataA, MyData dataB) {
                                int result;
                                if((result = Integer.compare(dataA.id, dataB.id)) == 0 &&
                                   (result = Boolean.compare(dataA.relevant, dataB.relevant)) == 0 &&
                                   (result = dataA.name.compareTo(dataB.name)) == 0)
                                    result = Float.compare(dataA.value, dataB.value);
                                return result;
                            }
                        }
                        

                        如果您只是想按自定义顺序对集合进行排序,那么以下内容更加简洁:

                        myDataList.sort((dataA, dataB) -> {
                            int result;
                            if((result = Integer.compare(dataA.id, dataB.id)) == 0 &&
                               (result = Boolean.compare(dataA.relevant, dataB.relevant)) == 0 &&
                               (result = dataA.name.compareTo(dataB.name)) == 0)
                                result = Float.compare(dataA.value, dataB.value);
                            return result;
                        });
                        

                        【讨论】:

                          【解决方案18】:

                          如果您实现Comparable 接口,您将需要选择一个简单的属性进行排序。这称为自然排序。将其视为默认值。当没有提供特定的比较器时,总是使用它。通常这是名称,但您的用例可能需要不同的名称。您可以随意使用可以提供给各种集合 API 的任意数量的其他比较器来覆盖自然顺序。

                          另请注意,通常如果 a.compareTo(b) == 0,则 a.equals(b) == true。如果没有也没关系,但有副作用需要注意。请参阅 Comparable 界面上出色的 javadocs,您会发现很多关于此的重要信息。

                          【讨论】:

                            【解决方案19】:

                            以下博客给出了良好的链式比较器示例

                            http://www.codejava.net/java-core/collections/sorting-a-list-by-multiple-attributes-example

                            import java.util.Arrays;
                            import java.util.Comparator;
                            import java.util.List;
                            
                            /**
                             * This is a chained comparator that is used to sort a list by multiple
                             * attributes by chaining a sequence of comparators of individual fields
                             * together.
                             *
                             */
                            public class EmployeeChainedComparator implements Comparator<Employee> {
                            
                                private List<Comparator<Employee>> listComparators;
                            
                                @SafeVarargs
                                public EmployeeChainedComparator(Comparator<Employee>... comparators) {
                                    this.listComparators = Arrays.asList(comparators);
                                }
                            
                                @Override
                                public int compare(Employee emp1, Employee emp2) {
                                    for (Comparator<Employee> comparator : listComparators) {
                                        int result = comparator.compare(emp1, emp2);
                                        if (result != 0) {
                                            return result;
                                        }
                                    }
                                    return 0;
                                }
                            }
                            

                            调用比较器:

                            Collections.sort(listEmployees, new EmployeeChainedComparator(
                                            new EmployeeJobTitleComparator(),
                                            new EmployeeAgeComparator(),
                                            new EmployeeSalaryComparator())
                                    );
                            

                            【讨论】:

                              【解决方案20】:

                              Steve's answer开始可以使用三元运算符:

                              public int compareTo(Person other) {
                                  int f = firstName.compareTo(other.firstName);
                                  int l = lastName.compareTo(other.lastName);
                                  return f != 0 ? f : l != 0 ? l : Integer.compare(age, other.age);
                              }
                              

                              【讨论】:

                                【解决方案21】:

                                用java中的hashcode方法比较两个对象很容易`

                                public class Sample{
                                
                                  String a=null;
                                  String b=null;
                                
                                  public Sample(){
                                      a="s";
                                      b="a";
                                  }
                                  public Sample(String a,String b){
                                      this.a=a;
                                      this.b=b;
                                  }
                                  public static void main(String args[]){
                                      Sample f=new Sample("b","12");
                                      Sample s=new Sample("b","12");
                                      //will return true
                                      System.out.println((s.a.hashCode()+s.b.hashCode())==(f.a.hashCode()+f.b.hashCode()));
                                
                                      //will return false
                                      Sample f=new Sample("b","12");
                                      Sample s=new Sample("b","13");
                                      System.out.println((s.a.hashCode()+s.b.hashCode())==(f.a.hashCode()+f.b.hashCode()));
                                
                                }
                                

                                【讨论】:

                                • 请不要这样做。 哈希码不应该用于相等比较,而是用于哈希表索引。哈希冲突可能导致两个不同对象相等。如果发生哈希冲突,即使哈希表也依赖于真正的相等性
                                【解决方案22】:

                                使用Google's Guava library 很容易做到。

                                例如Objects.equal(name, name2) &amp;&amp; Objects.equal(age, age2) &amp;&amp; ...

                                更多示例:

                                【讨论】:

                                • 比较事物不同于执行相等性检查
                                猜你喜欢
                                • 1970-01-01
                                • 1970-01-01
                                • 1970-01-01
                                • 1970-01-01
                                • 1970-01-01
                                • 1970-01-01
                                • 2017-02-24
                                相关资源
                                最近更新 更多