使用Java8为类中任意数量的字段构建比较器逻辑
我正在尝试使用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 {
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.