如何使用单个比较器对对象中的所有字段进行排序?
例如:如果我有Employee
个对象,其中有三个字段,例如Name
,Eid
和Salary
。我不需要编写三个比较器,即Namecomparator
,Eidcomparator
和Salarycomparator
进行排序,而只需要一个比较器,它可以根据我动态提供的字段进行排序。
答案 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();
}
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();
}