首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >类中任意字段使用Java 8构建比较器逻辑

类中任意字段使用Java 8构建比较器逻辑
EN

Stack Overflow用户
提问于 2021-02-08 14:27:41
回答 3查看 173关注 0票数 2

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

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

这意味着比较逻辑应该是这样的: id -> name --> newfield1 --> newfield2

见下面的伪代码:

代码语言:javascript
运行
复制
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;
    }
    
    
    
}
EN

回答 3

Stack Overflow用户

发布于 2021-02-10 08:36:54

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

代码语言:javascript
运行
复制
<dependency>
   <groupId>commons-beanutils</groupId>
   <artifactId>commons-beanutils</artifactId>
   <version>1.9.3</version>
</dependency>

简单的例子:

代码语言:javascript
运行
复制
public static <T> Comparator<T> beanComparator(String fieldName, boolean asc) {
    Comparator<T> propertyComparator;
    if (asc) {
        propertyComparator = new BeanComparator<>(fieldName);
    } else {
        propertyComparator = new ReverseComparator(new BeanComparator<>(fieldName));
    }
    return propertyComparator;
}
票数 1
EN

Stack Overflow用户

发布于 2021-02-08 18:13:55

要做您想要做的事情是有问题的,因为您需要使用反射将一个函数(它描述一个返回类型)传递给比较器。因为我认为您无论如何都需要修改类,以包含新字段以及它们的getter和构造函数。通过这样做,您可以指定在比较中应用getter的顺序。

代码语言:javascript
运行
复制
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;
    }
    
}

然后你就可以这样称呼它。

代码语言:javascript
运行
复制
List<Person> sortedPersons = persons.stream().sorted()
        .collect(Collectors.toList());

或者如果他们已经在List

代码语言:javascript
运行
复制
persons.sort(null); // null == natural ordering.
票数 0
EN

Stack Overflow用户

发布于 2021-02-10 23:15:18

您可以使用Field.get方法,它返回作为参数传递的对象上该字段的值。get抛出一个已检查的异常,因此我们必须捕获它并作为一个未检查的异常重新抛出。

代码语言:javascript
运行
复制
Field[] fields = Person.class.getDeclaredFields();

Comparator<Person> comparator = Comparator.comparing(Person::getId);
for (int i = 1; i < fields.length; i++) {
    // variable referenced in lambda must be final or effectively final
    final Field f = fields[i];
    
    comparator = comparator.thenComparing((Person person) -> {
        try {
            return (Comparable) f.get(person);
        } catch(IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    });
}

这将导致关于未检查的方法调用和未检查的转换的警告,这可以通过方法上的@SuppressWarnings("unchecked")注释来抑制。警告是真实的:如果Person有一个类型不是Comparable的字段,那么这将在运行时失败。您可能希望先检查f的类型是否实现了Comparable,并且只更新比较器;我没有为您这样做。

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

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/66103523

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档