假设我有一个带有多个String字段的java对象。
public class Person {
private String field1
// keeps going
我希望能够根据我选择的任何字段对人员列表进行排序。
我知道我可以使用比较器接口并实现多个compareTo,如主题所述:How do I make 2 comparable methods in only one class?
但在使用Collections.sort()
但是如果没有这些重复的代码,我有什么方法可以做到这一点吗?
答案 0 :(得分:8)
如果您不喜欢Comparator
类的详细程度,那么请使用Java 8及其lambda表达式:
Comparator<Person> byName = Comparator.comparing(Person::getName);
Comparator<Person> byBirthDate = Comparator.comparing(Person::getBirthDate);
答案 1 :(得分:3)
我希望能够对人员列表进行排序 取决于我选择的任何领域。
@JB Nizet Java 8 的解决方案将成为一个技巧,但它仅适用于Java 8.低于8的版本怎么样?被大多数人使用?
我将为您提供我认为比Java 8更低版本的简单解决方案。
你真的不需要创建多个Comparator
课程(你提到它为#34;重复代码&#34;)。如何使用适当的技术,如条件或枚举?
private Comparator<YourClass> getComparator(MyPropertiesEnum myEnum) {
return new Comparator<YourClass>() {
@Override
public int compare(YourClass o1, YourClass o2) { {
switch (myEnum) {
case FIRSTNAME:
// implementation for firstname
break;
case LASTNAME:
// implementation for lastname
break;
default:
// implementation for default version
break;
}
}
};
}
MyPropertiesEnum
的位置如下:
public enum MyPropertiesEnum {
FIRSTNAME, LASTNAME, AGE;
}
注意:如果条件适合您,也可以使用正确的条件。
希望它能帮助您解决问题。
答案 2 :(得分:1)
public class Person {
private String field1;
private String field2;
...
private Map<String,String> allFields;
...
public void setField1 (String value) {
field1 = value;
allFields.put("field1",value);
}
public void setField2 (String value) {
field2 = value;
allFields.put("field2",value);
}
或者你想要的任何名字。或者,您可以使用enum
代替String
作为地图密钥。这说明为什么顺便说一句,使用getter和setter是一个好主意;你不能通过使用公共成员字段并让客户直接分配给他们来做到这一点。但是,由于您创建字段private
并需要设置器来设置它们,因此您可以确保String
字段和地图条目始终匹配。
现在,通过在Comparator
中查找所需的字段,可以轻松编写单个allFields
。
答案 3 :(得分:1)
这是一种通用方法的草图。
只要字段的类型实现compareTo
方法(也就是说,你应该使用Integer vs int等),它应该可以工作。
免责声明:我没有考虑任何性能问题:)
Sorter.java
package sovflow;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class Sorter<ObjectType, FieldType extends Comparable<FieldType>> {
public List<Wrapper<ObjectType, FieldType>> sort(List<ObjectType> list,
Field field) {
field.setAccessible(true);
List<Wrapper<ObjectType, FieldType>> _list = new ArrayList<Wrapper<ObjectType, FieldType>>();
for (ObjectType object : list) {
Wrapper<ObjectType, FieldType> wrapper = new Wrapper<ObjectType, FieldType>(
field, object);
_list.add(wrapper);
}
Collections.sort(_list);
return _list;
}
}
Wrapper.java
package sovflow;
import java.lang.reflect.Field;
public class Wrapper<ObjectType, FieldType extends Comparable<FieldType>>
implements Comparable<Wrapper<ObjectType, FieldType>> {
Field field;
ObjectType object;
public Wrapper(Field field, ObjectType object) {
this.field = field;
this.object = object;
}
@SuppressWarnings("unchecked") // for the field.get. Unavoidable, i'd say :)
public int compareTo(Wrapper<ObjectType, FieldType> paramT) {
try {
return ((FieldType) field.get(object)).compareTo((FieldType)field.get(paramT.object));
} catch (Exception e) {
e.printStackTrace();
}
return 0;
}
public void print() {
System.out.println(object);
}
}
这是如何使用它的一个例子:
package sovflow;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
public class Main {
private static class Person {
private Integer id;
private String name;
public Person(Integer id, String name) {
super();
this.id = id;
this.name = name;
}
@Override
public String toString() {
return "Id = " + id + " name = " + name;
}
}
public static void main(String[] args) {
Person p = new Person(1, "B");
Person p2 = new Person(2, "A");
List<Person> list = new ArrayList<Person>();
list.add(p);
list.add(p2);
Sorter<Person, String> sorter = new Sorter<Person, String>();
try {
Field declaredField = Person.class.getDeclaredField("name");
// Just to show the result. The sort method could be modified to
// not having to deal with the wrapper here..
List<Wrapper<Person,String>> list2 = sorter.sort(list, declaredField);
for (Wrapper<Person, String> wrapper : list2) {
wrapper.print();
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}