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

Java 8 根据对象的参数化属性对对象列表进行排序,java-8,Java 8,假设我们有一个具有以下属性的对象: public class MyObject { private String attr1; private Integer attr2; //... public String getAttr1() { return this.attr1; } public Integer getAttr2() { return this.attr2; } } 根据此对象的属性属

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

public class MyObject {

    private String attr1;
    private Integer attr2;

    //...

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

    public Integer getAttr2() {
        return this.attr2;
    }
}
根据此对象的属性属性对列表进行排序的一种方法是:

mylist.sort(Comparator.comparing(MyObject::getAttr1));
是否可以在方法内部以动态方式使用此代码,并将
getAttr1
部分替换为基于对象名称返回对象属性getter的方法?比如:

public void sortListByAttr(List<MyObject> list, String attr) {
    list.sort(Comparator.comparing(MyObject::getGetterByAttr(attr)));
}
public void sortListByAttr(列表,字符串attr){
list.sort(Comparator.comparing(MyObject::getterbyattr(attr));
}
MyObject::getGetterByAttr(attr)部分没有编译,我写它只是作为一个例子来解释我的想法


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

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

public void sortListByAttr(List<MyObject> list, String attr) {
    list.sort(getComparator(attr));
}

只有通过反射才能实现更大的动态性,但这会使代码复杂化,添加大量潜在的错误源,但好处很小,考虑到您只需要添加一行源代码即可添加对上述任一示例中另一个属性的支持。毕竟,定义的属性集在编译时是固定的。

您也可以在一个地方定义这个比较器:

 static enum MyObjectComparator {

    ATTR1("attr1", Comparator.comparing(MyObject::getAttr1));

    MyObjectComparator(String attrName, Comparator<MyObject> comparator) {
        this.comparator = comparator;
        this.attrName = attrName;
    }

    private final Comparator<MyObject> comparator;

    private final String attrName;

    private static MyObjectComparator[] allValues = MyObjectComparator.values();

    public static Comparator<MyObject> findByValue(String value) {
        return Arrays.stream(allValues)
                .filter(x -> x.attrName.equalsIgnoreCase(value))
                .map(x -> x.comparator)
                .findAny()
                .orElseThrow(RuntimeException::new);
    }

}
静态枚举MyObjectComparator{
ATTR1(“ATTR1”,Comparator.comparing(MyObject::getAttr1));
MyObjectComparator(字符串属性名,Comparator Comparator){
这个比较器=比较器;
this.attrName=attrName;
}
私人最终比较人;
私有最终字符串attrName;
私有静态MyObjectComparator[]allValues=MyObjectComparator.values();
公共静态比较器findByValue(字符串值){
返回Arrays.stream(所有值)
.filter(x->x.attrName.equalsIgnoreCase(值))
.map(x->x.comparator)
.findAny()
.orelsetrow(运行时异常::新建);
}
}
你的用法是:

public void sortListByAttr(List<MyObject> list, String attr) {
    list.sort(MyObjectComparator.findByValue(attr));
}
public void sortListByAttr(列表,字符串attr){
sort(MyObjectComparator.findByValue(attr));
}

首先,向上投票。我也希望使用枚举来实现这一点。如果您将
findByValue
重命名为
by
,我认为它更有意义。@holi java这实际上是我在许多项目中看到的一种模式(主要是Spring),所以我有点习惯了。是的,具体介绍一个枚举,我们可以获取更多信息,以OO方式实现它。然后我们可以编写一些东西,如
sort(by(“attr1”).comparator)
process(by(“attr1”).getter)
 static enum MyObjectComparator {

    ATTR1("attr1", Comparator.comparing(MyObject::getAttr1));

    MyObjectComparator(String attrName, Comparator<MyObject> comparator) {
        this.comparator = comparator;
        this.attrName = attrName;
    }

    private final Comparator<MyObject> comparator;

    private final String attrName;

    private static MyObjectComparator[] allValues = MyObjectComparator.values();

    public static Comparator<MyObject> findByValue(String value) {
        return Arrays.stream(allValues)
                .filter(x -> x.attrName.equalsIgnoreCase(value))
                .map(x -> x.comparator)
                .findAny()
                .orElseThrow(RuntimeException::new);
    }

}
public void sortListByAttr(List<MyObject> list, String attr) {
    list.sort(MyObjectComparator.findByValue(attr));
}