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

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()等)是混乱的。

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


当前回答

晚做总比不到好——如果你正在寻找不必要的混乱或开销,那么很难同时在最少的代码/快速执行方面击败下面的方法。

数据类:

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

其他回答

如果用户有多种方式对人排序,你也可以在某个地方设置多个comparator常量。大多数排序操作和排序集合都以比较器作为参数。

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

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

    }

}

你也可以看看实现Comparator的Enum。

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

e.g.

Collections.sort(myChildren, Child.Order.ByAge.descending());
//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);