假设你有一些对象,它们有几个字段可以比较:

public class Person {

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

    /* Constructors */

    /* Methods */

}

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

a.compareTo(b) > 0

你可能会问a的姓是不是在b的姓之前,或者a的年龄是不是比b大,等等……

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

comparable接口只允许通过一个字段进行比较 在我看来,添加大量的比较方法(如compareByFirstName(), compareByAge()等)是混乱的。

那么最好的解决办法是什么呢?


当前回答

如果实现Comparable接口,则需要选择一个简单的属性进行排序。这就是所谓的自然排序。把它看作默认值。通常在没有提供特定比较器时使用。通常这是名称,但您的用例可能调用不同的东西。您可以自由地使用任何数量的其他比较器,您可以提供给各种集合api来覆盖自然排序。

还要注意,通常如果a.c omareto (b) == 0,则a.c omareto (b) == true。如果没有也没关系,但是有副作用要注意。在Comparable接口上查看优秀的javadocs,您将找到许多关于这方面的有用信息。

其他回答

从Steve的回答开始,三元操作符可以使用:

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);
}

我认为如果你的比较算法是“聪明的”,那就更令人困惑了。我会选择你建议的众多比较方法。

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

//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());
        });

    }

}

Java 8通过lambda方式我们可以通过方法引用进行比较。 学生POJO

public class Student {
int id;
String firstName;
String lastName;
String subject;

public Student(int id, String firstName, String lastName, String subject) {
    this.id = id;
    this.firstName = firstName;
    this.lastName = lastName;
    this.subject = subject;
}
enter code here

现在我们可以根据

1. id - > FirstName - > LastName - > 2。主题- > id - > FirstName - > LastName

我们将在数组Stream中使用Comparator

public class TestComprator {
public static void main(String[] args) {
    Student s1= new Student(108, "James", "Testo", "Physics");
    Student s2= new Student(101, "Fundu", "Barito", "Chem");
    Student s3= new Student(105, "Sindhu", "Sharan", "Math");
    Student s4= new Student(98, "Rechel", "Stephen", "Physics");
    System.out.printf("----------id->FirstName->LastName->Subject-------------");
    Arrays.asList(s1,s2,s3,s4).stream()
            .sorted(Comparator.comparing(Student::getId)
                    .thenComparing(Student::getFirstName)
                .thenComparing(Student::getLastName)
                .thenComparing(Student::getSubject))
            .forEach(System.out::println);

    System.out.printf("----Subject->id->FirstName->LastName ------\n");
    Arrays.asList(s1,s2,s3,s4).stream()
            .sorted(Comparator. comparing(Student::getSubject)
                    .thenComparing(Student::getId)
                    .thenComparing(Student::getFirstName)
                    .thenComparing(Student::getLastName)
                   )
            .forEach(System.out::println);
}

}

输出:

`----------id->FirstName->LastName->Subject-------------
Student{id=98, firstName='Rechel', lastName='Stephen', subject='Physics'}
Student{id=101, firstName='Fundu', lastName='Barito', subject='Chem'}
Student{id=105, firstName='Sindhu', lastName='Sharan', subject='Math'}
Student{id=108, firstName='James', lastName='Testo', subject='Physics'}
 ----Subject->id->FirstName->LastName ------
Student{id=101, firstName='Fundu', lastName='Barito', subject='Chem'}
Student{id=105, firstName='Sindhu', lastName='Sharan', subject='Math'}
Student{id=98, firstName='Rechel', lastName='Stephen', subject='Physics'}
Student{id=108, firstName='James', lastName='Testo', subject='Physics'}

在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()));

}