我有一个Report {String name, Date date, int score }
课程。
我希望能够使用新的java 8语法
所以java 8提供了这个新的
list.sort(Comparator.comparing(report -> report.name))
对名单上的列表进行排序。
让我们说代替名字我想为这个方法提供一个变量字段名称,例如。
之类的东西list.sort(Comparator.comparing(report -> report.anyField))
其中anyField可以是名称或日期或分数。我该如何实现这种行为。
答案 0 :(得分:4)
只需为每个属性创建一个比较器。
static Map<String,Comparator<Report>> ORDER;
static {
HashMap<String,Comparator<Report>> m=new HashMap<>();
m.put("name", Comparator.comparing(r -> r.name));
m.put("date", Comparator.comparing(r -> r.date));
m.put("score", Comparator.comparingInt(r -> r.score));
ORDER=Collections.unmodifiableMap(m);
}
public static void sort(List<Report> list, String order) {
Comparator<Report> c=ORDER.get(order);
if(c==null) throw new IllegalArgumentException(order);
list.sort(c);
}
您可以考虑使用enum
替代String
,这样就无法提供不存在的属性名称:
enum ReportOrder {
NAME(Comparator.comparing(r -> r.name)),
DATE(Comparator.comparing(r -> r.date)),
SCORE(Comparator.comparingInt(r -> r.score));
private Comparator<Report> cmp;
private ReportOrder(Comparator<Report> c) { cmp=c; }
public void sort(List<Report> list) {
list.sort(cmp);
}
}
现在你可以说,例如ReportOrder.NAME.sort(list);
。当然,其他代表团风格也适用:
public static void sort(List<Report> list, ReportOrder o) {
list.sort(o.cmp);
}
sort(list, ReportOrder.DATE);
答案 1 :(得分:2)
一个非常通用的解决方案是使用Java的Reflection和一些转换:
String sortBy = "name";
list.sort(Comparator.comparing(report -> {
try {
return (Comparable) report.getClass().getDeclaredField(sortBy).get(report);
} catch (Exception e) {
throw new RuntimeException("Ooops", e);
}
}));
如果您使用https://github.com/jOOQ/jOOR之类的其他库,则代码变得更加简单:
String sortBy = "score";
list.sort(Comparator.comparing(report -> Reflect.on(report).field(sortBy).get()));
请注意,此解决方案仅适用于实现Comparable
的字段,并且它具有一些运行时开销。
答案 2 :(得分:0)
如果您的报告具有各种字段的getter方法,您可以这样做
list.sort(Comparator.comparing(Report::getFieldName));
或使用lambda表达式
list.sort((ob1, ob2) -> ob1.getFieldName().compareTo(ob2.getFieldName()));
答案 3 :(得分:0)
在某个地方,你将不得不使用一点反射来解决这个问题。这是一个使用java的bean内省机制的例子:
public static class MyBean {
private String name;
private Date birthday;
private Integer score;
...
... (constructor, getters, setters - the usual bean stuff)
}
PropertyDescriptor[] pdesc = Introspector.getBeanInfo(MyBean.class).getPropertyDescriptors();
for(PropertyDescriptor pd : pdesc) {
if(Comparable.class.isAssignableFrom(pd.getPropertyType())) {
System.out.println("Property " + pd.getName() + " could be used for comparison");
Function<MyBean, Comparable> extractor = b -> {
try {
return (Comparable) pd.getReadMethod().invoke(b);
}
catch(Exception e) {
throw new RuntimeException(e);
}
};
Comparator<MyBean> comp = Comparator.comparing(extractor);
// do something useful with the comparator :-)
}
}
此外,您可以采用类似的方式处理基本类型(例如,int,它不实现Comparable而不是Integer。)
答案 4 :(得分:0)
如果修复了一组属性(名称,日期,分数),那么我认为干净的方法是通过比较器:
private void someMethod(Comparator<Report> comparator){
...
list.sort(comparator);
...
}
...
someMethod(Comparator.comparing(report::getName));
someMethod(Comparator.comparing(report::getDate));
someMethod(Comparator.comparingInt(report::getScore));
someMethod(Comparator.comparing(report::getName).thenComparingInt(report::getScore));
答案 5 :(得分:0)
有一个名为NamedMethodComparator的Comparator类,它将作为任何零arg方法的比较器,返回此处发布的Comparable:How to use Comparator in Java to sort
答案 6 :(得分:0)
public class Report {
//properties and getters
public static void sort(List<Report> list, Function<Report, Comparable> sortKey) {
list.sort(Comparator.comparing(sortKey));
}
}
Report.sort(reports, Report::getName);
Report.sort(reports, Report::getDate);
Report.sort(reports, Report::getScore);
可以使它成为通用的util类,您可以在其中传递任何类的列表:
public class MyUtil<T> {
void sort(List<T> t, Function<T, Comparable> sortKey) {
t.sort(Comparator.comparing(sortKey));
}
}
MyUtil<Report> util = new MyUtil();
util.sort(ppl, Report::getName);