使用Java8为类中任意数量的字段构建比较器逻辑

使用Java8为类中任意数量的字段构建比较器逻辑,java,java-8,comparator,Java,Java 8,Comparator,我正在尝试使用Java8中引入的Comparator.comparating()构建自定义比较逻辑 要求是:如果在Person类中引入了一个新字段,代码应该可以工作。它应该将新领域纳入比较逻辑 这意味着比较逻辑应该是这样的:id-->名称-->新字段1-->新字段2 请参见下面的伪代码: package test; import java.lang.reflect.Field; import java.util.Comparator; public class Test6 {

我正在尝试使用Java8中引入的
Comparator.comparating()
构建自定义比较逻辑

要求是:如果在Person类中引入了一个新字段,代码应该可以工作。它应该将新领域纳入比较逻辑

这意味着比较逻辑应该是这样的:id-->名称-->新字段1-->新字段2

请参见下面的伪代码:

package test;

import java.lang.reflect.Field;
import java.util.Comparator;

public class Test6 {
    
    public static void main (String args []) {
        Field[] declaredFields = Person.class.getDeclaredFields();
        
        Comparator<Person> comparator = Comparator.comparing((Person x)-> x.getId());
        for (int i=1; i<declaredFields.length ; i++) {
            comparator = comparator.thenComparing(field[i]);  // what code should I place over here, to make it work for field obtained above.
        }

   List<Person> persons = new ArrayList<>();
     persons.stream().sorted(comparator).collect(Collectors.toList());
    }


}

class Person{
    int id ;
    String name;
    // if we add new field , then this field should also be included in comparison logic

    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    
    
    
}
封装测试;
导入java.lang.reflect.Field;
导入java.util.Comparator;
公共类测试6{
公共静态void main(字符串参数[]){
Field[]declaredFields=Person.class.getDeclaredFields();
Comparator Comparator=Comparator.comparing((Person x)->x.getId());

for(int i=1;i执行您试图执行的操作是有问题的,因为您需要传递一个函数(该函数将描述返回类型)由于我假定您无论如何都需要修改类,以包含新字段及其getter和构造函数。通过这种方式,您可以指定在比较中应用getter的顺序

class Person implements Comparable<Person> {
    int id;
    String name;
    String foo;

    private Comparator<Person> comparing = Comparator.comparing(Person::getId);
  
    {
        comparing = comparing.thenComparing(Person::getName);
        comparing = comparing.thenComparing(Person::getFoo);
        // as new fields/getters are added, also append (or insert) the 
        // comparator.
    }
    
    public int getId() {
        return id;
    }
    
    public void setId(int id) {
        this.id = id;
    }
    
    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
    public int compareTo(Person p) {
        return comparing.compare(this, p);
    }
    
    public String getFoo() {
        return foo;
    }
    
}

在Apache Commons BeanUtils中,有一个基于反射的有用的比较器
BeanComparator
。结合ReverseComparator,可以编写动态比较器


公地小海狸
公地小海狸
1.9.3
简单的例子:

publicstaticcomparatorbeancomparator(字符串字段名,布尔asc){
比较器性能比较器;
如果(asc){
propertyComparator=新的BeanComparator(字段名);
}否则{
propertyComparator=new ReverseComparator(new BeanComparator(fieldName));
}
返回属性比较程序;
}
您可以使用该方法,该方法返回作为参数传递的对象上该字段的值。
get
抛出一个选中的异常,因此我们必须捕获它并作为未选中的异常重新抛出

Field[]fields=Person.class.getDeclaredFields();
Comparator-Comparator=Comparator.comparing(Person::getId);
for(int i=1;i{
试一试{
收益(可比)f.get(人);
}捕获(非法访问例外e){
抛出新的运行时异常(e);
}
});
}
这将导致有关未经检查的方法调用和未经检查的转换的警告,可以使用
@SuppressWarnings(“未经检查”)来抑制这些警告
方法上的注释。警告是真实的:如果
Person
具有类型不可比的字段,则在运行时此操作将失败。您可能希望首先检查
f
的类型是否实现了
可比的
,如果有,则仅更新比较器;我没有为您这样做


还请注意,如果
id
不再是数组中的第一个字段,则从索引1开始循环的代码可能会中断;我建议简单地在整个数组上循环,这将第二次多余地包括
id
字段,但这不会造成任何损害,只会带来较小的性能成本。

在帖子中明确你的问题是什么。实现
equals
hashCode
Comparable
。你完成了。@MAnouti编辑的问题,你能检查一下吗again@ASharma7可能不会,但我的意思是,使用反射来构建比较器太麻烦了。你需要检查字段类型,然后不知何故你需要告诉reflective代码应该如何比较字段。这并不聪明。除非您指定字段比较的顺序,否则使用compareTo(或comparator)是没有意义的。您打算怎么做?您看过getDeclaredFields()javadoc吗“返回数组中的元素未排序,且未按任何特定顺序排列”?
List<Person> sortedPersons = persons.stream().sorted()
        .collect(Collectors.toList());
persons.sort(null); // null == natural ordering.