考虑我有两个不同的 POJO 类,如下所示。
class Employee {
String empId;
Date empJoiningDate;
BigDecimal empExperience;
}
class EmployeeDetails {
String empName;
String address;
BigDecimal contactNo;
Date empdob;
}
需要创建通用方法,通过该方法我可以对 Employee 或 EmployeeDetails 进行排序
sortbyProperty(List<T> list, String columnName, boolean ascOrder)
尝试使用以下代码,但无法动态执行。
empList.stream().sorted(Comparator.comparing(Employee::getEmpId())).collect(Collectors.toList())
这实现和使用起来很麻烦:
Comparator
将是原始的,除非我们定义 Class<R>
参数,其中 <R extends Comparable<R>>
(答案结束)。Class<T>
参数。使用 Stream API 和比较器进行排序本身很简单。我们剩下的就是实现比较器。
考虑这个方法:
private <T> List<T> sortByProperty(List<T> list, Class<T> type, String columnName, boolean ascOrder) {
return list.stream()
.sorted(dynamicComparator(type, columnName, ascOrder))
.toList();
}
比较器看起来像这样:
private <T> Comparator dynamicComparator(Class<T> type, String fieldName, boolean ascOrder) {
final var method = Arrays.stream(type.getMethods())
.filter(m -> m.getName().equals("get" + capitalize(fieldName))
|| m.getName().equals("is" + capitalize(fieldName)))
.findFirst()
.orElseThrow(() -> new IllegalArgumentException("No getter for " + fieldName));
return (o1, o2) -> {
try {
final var left = method.invoke(o1);
final var right = method.invoke(o2);
if (left instanceof Comparable comparableLeft && right instanceof Comparable comparableRight) {
return ascOrder
? comparableLeft.compareTo(comparableRight)
: comparableRight.compareTo(comparableLeft);
} else {
throw new IllegalArgumentException(fieldName + " is not comparable");
}
} catch (IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
};
}
另外,这是需要的:
private String capitalize(String string) {
return string.substring(0, 1).toUpperCase() + string.substring(1);
}
带有附加
Class<R>
参数的比较器大致如下(未经测试):
private <T, R extends Comparable<R>> Comparator<T> dynamicComparator(Class<T> type, String fieldName, Class<R> columnType, boolean ascOrder) {
return (o1, o2) -> {
try {
final R left = (R) method.invoke(o1);
final R right = (R) method.invoke(o2);
return ascOrder ? left.compareTo(right) : right.compareTo(left);
} catch (ClassCastException e) {
throw new IllegalArgumentException(fieldName + " is not comparable");
} catch (InvocationTargetException | IllegalAccessException e) {
throw new RuntimeException(e);
}
};
}