我们如何在Comparator.comparing中传递变量字段/方法名称

时间:2016-09-13 06:05:49

标签: java java-8

我有一个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可以是名称或日期或分数。我该如何实现这种行为。

7 个答案:

答案 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);