如何仅使用一个Comparator对对象中的所有字段进行排序?

时间:2014-12-21 15:12:03

标签: java comparator

如何使用单个比较器对对象中的所有字段进行排序?

例如:如果我有Employee个对象,其中有三个字段,例如NameEidSalary。我不需要编写三个比较器,即NamecomparatorEidcomparatorSalarycomparator进行排序,而只需要一个比较器,它可以根据我动态提供的字段进行排序。

2 个答案:

答案 0 :(得分:9)

  

不是编写3个比较器,即Namecomparotor,Eidcomparotor和Salarycomparotor进行排序,我只需要一个可以根据我动态提供的字段进行排序的比较器。

使用Java 8,如果所有这些字段都有get方法,则可以使用Comparator.comparing

Collections.sort(employees, Comparator.comparing(Employee::getSalary);

如果你想按多个标准排序(打破关系),你可以使用thenComparing

Collections.sort(employees, Comparator.comparing(Employee::getSalary)
                                      .thenComparing(Employee::getName)
                                      .thenComparing(Employee::getId));

在这两种情况下,您只需将该字段作为Function进行排序即可创建自定义Comparator。或者,您也可以使用lambda expression按各种其他标准进行排序:

Collections.sort(employees, Comparator.comparing(e -> e.getName.length()));

如果您使用的是旧版本的Java(并且无法升级到Java 8),您可以创建自己的Function类和相应的通用Comparator

abstract class CompareFunction<A> {
    abstract public Comparable apply(A object);
}

class FunctionComparator<T> implements Comparator<T> {
    final CompareFunction<T> function;
    public FunctionComparator(CompareFunction<T> function) {
        this.function = function;
    }
    public int compare(T a, T b) {
        return function.apply(a).compareTo(function.apply(b));
    }
}

用法:

Collections.sort(employees, new FunctionComparator<Employee>(new CompareFunction<Employee>() {
    public Comparable apply(Employee object) {
        return object.getSalary();
    };
}));

或者将它与Java Reflextion结合使用,根据getter方法的名称创建这样的比较器:

public static <T> Comparator<T> createGetterComparator(Class<T> clazz, String getterName) throws Exception {
    final Method getter = clazz.getMethod(getterName);
    return new FunctionComparator<T>(new CompareFunction<T>() {
        public Comparable apply(T object) {
            try {
                return (Comparable) getter.invoke(object);
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }
    });
}

用法:

Collections.sort(employees, createGetterComparator(Employee.class, "getSalary"));

答案 1 :(得分:5)

使用类似按id排序的东西,然后命名为salary:

public class EmployeeComparator implements Comparator<Employee> {
    public int compare(Employee e1, Employee e2) {
        if (e1 == e2) {
           return 0;
        } 
        if (e1 == null && e2 != null) {
            return -1;
        }
        if (e1 != null && e2 == null) {
            return -1;
        }
        if (e1.getId().equals(e2.getId())) {
            if (e1.getName().equals(e2.getName())) {
                if (e1.getSalary() == e2.getSalary()) {
                    return 0;
                } else {
                    return int(e1.getSalary() - e2.getSalary());
                }
            } else {
                 return e1.getName().compareTo(e2.getName());
            }
        } else {
            return e1.getId().compareTo(e2.getId());
        }
    }
}

如果您需要上述简洁版,则需要使用Guava's ComparisonChain,如下所示:

    @Override  
    public int compare(Employee e1, Employee e2) {  
        return ComparisonChain.start() 
           .compare(e1.getId(), e2.getId(), Ordering.natural().nullsLast()) 
           .compare(e1.getName(), e2.getName(), Ordering.natural().nullsLast()) 
           .compare(e1.getSalary(), e2.getSalary(), Ordering.natural().nullsLast()) 
           .result(); 
   }  

apache's CompareToBuilder如下:

public int compare(Employee e1, Employee e2) {  
    return new CompareToBuilder().append(e1.getId(), e2.getId()).append(e1.getName(), e2.getName()).append(e1.getSalary(), e2.getSalary()).toComparison();  
}  
相关问题