根据对象的参数化属性对对象列表进行排序

Str*_*der 2 java-8

假设我们有一个具有以下属性的对象:

public class MyObject {

    private String attr1;
    private Integer attr2;

    //...

    public String getAttr1() {
        return this.attr1;
    }

    public Integer getAttr2() {
        return this.attr2;
    }
}
Run Code Online (Sandbox Code Playgroud)

mylist根据其属性对此对象的列表进行排序的一种方法attr1是:

mylist.sort(Comparator.comparing(MyObject::getAttr1));
Run Code Online (Sandbox Code Playgroud)

是否可以以动态方式在方法中使用此代码,并使用getAttr1根据其名称返回对象属性的getter的方法替换该部分?就像是:

public void sortListByAttr(List<MyObject> list, String attr) {
    list.sort(Comparator.comparing(MyObject::getGetterByAttr(attr)));
}
Run Code Online (Sandbox Code Playgroud)

MyObject::getGetterByAttr(attr)部分不编译,我写的只是作为一个例子来解释我的想法

我尝试使用以下代码实现一个方法new PropertyDescriptor(attr, MyObject.class).getReadMethod().invoke(new MyObject())但是仍然无法使用该方法中的参数调用comparing方法

Hol*_*ger 6

你可以添加像这样的方法

public static Function<MyObject,Object> getGetterByAttr(String s) {
    switch(s) {
        case "attr1": return MyObject::getAttr1;
        case "attr2": return MyObject::getAttr2;
    }
    throw new IllegalArgumentException(s);
}
Run Code Online (Sandbox Code Playgroud)

到你的类,但返回的函数不适合Comparator.comparing,因为它期望一个类型满足U extends Comparable<? super U>,而且每个String并且Integer能够在单个调用中实现这个约束,没有办法声明泛型返回类型getGetterByAttr以允许这两种类型并仍然符合宣言comparing.

另一种选择是完整Comparator的工厂.

public static Comparator<MyObject> getComparator(String s) {
    switch(s) {
        case "attr1": return Comparator.comparing(MyObject::getAttr1);
        case "attr2": return Comparator.comparing(MyObject::getAttr2);
    }
    throw new IllegalArgumentException(s);
}
Run Code Online (Sandbox Code Playgroud)

用得像

public void sortListByAttr(List<MyObject> list, String attr) {
    list.sort(getComparator(attr));
}
Run Code Online (Sandbox Code Playgroud)

这具有以下优点:它还可以支持其类型不是Comparable并且需要定制的属性Comparator.此外,更有效的原始类型比较器(例如使用comparingInt)也是可能的.

您也可以考虑使用a Map而不是switch:

private static Map<String,Comparator<MyObject>> COMPARATORS;
static {
    Map<String,Comparator<MyObject>> comparators=new HashMap<>();
    comparators.put("attr1", Comparator.comparing(MyObject::getAttr1));
    comparators.put("attr2", Comparator.comparing(MyObject::getAttr2));
    COMPARATORS = Collections.unmodifiableMap(comparators);
}
public static Comparator<MyObject> getComparator(String s) {
    Comparator<MyObject> comparator = COMPARATORS.get(s);
    if(comparator != null) return comparator;
    throw new IllegalArgumentException(s);
}
Run Code Online (Sandbox Code Playgroud)

只有通过Reflection才能实现更多动态,但这会使代码复杂化,添加大量潜在的错误源,只有很少的好处,考虑到你只需要添加一行源代码来添加对任何一个属性的支持.上面的例子.毕竟,定义的属性集在编译时得到修复.