Использование Comparable для нескольких динамических полей VO в java
У меня есть класс
public class StudentVO {
int age;
String name;
}
Я использовал тот же класс в двух разных областях. В одном месте мне нужно сортировать по возрасту. В другом месте мне нужно сортировать по имени и в в другом месте мне может понадобиться сортировка на основе как возраста, так и имени. Как я могу это сделать? Если одно поле я может переопределить compareTo()
.
Можно ли это сделать?
Ответы
Ответ 1
1) Вы должны написать два Comparator для сортировки по возрасту и имени отдельно, а затем использовать Коллекции. сортировки (List, компаратор). Что-то вроде этого:
class StudentVO {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
class AgeComparator implements Comparator<StudentVO> {
@Override
public int compare(StudentVO o1, StudentVO o2) {
Integer age1 = o1.getAge();
Integer age2 = o2.getAge();
return age1.compareTo(age2);
}
}
class NameComparator implements Comparator<StudentVO> {
@Override
public int compare(StudentVO o1, StudentVO o2) {
return o1.getName().compareTo(o2.getName());
}
}
И затем используйте их, Чтобы отсортировать на основе age
:
Collections.sort(list,new AgeComparator());
для сортировки на основе name
:
Collections.sort(list,new NameComparator());
2) Если вы считаете, что List
of StudentVO
имеет некоторый естественный порядок сортировки, скажем, предположим, что сортировка выполняется по age
. Затем используйте Comparable для age
и Comparator
для name
.
class StudentVO implements Comparable<StudentVO>{
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public int compareTo(StudentVO o) {
return ((Integer)getAge()).compareTo(o.getAge());
}
}
class NameComparator implements Comparator<StudentVO> {
@Override
public int compare(StudentVO o1, StudentVO o2) {
return o1.getName().compareTo(o2.getName());
}
}
И затем используйте их, Чтобы отсортировать на основе age
:
Collections.sort(list);
для сортировки на основе name
:
Collections.sort(list,new NameComparator());
Ответ 2
Вот фрагмент кода:
public class StudentNameComparator implements Comparator<StudentVO>{
@Override
public int compare(StudentVO s1, StudentVO s2) {
//ascending order
return s1.getName().compareTo(s2.getName());
//descending order
//return s2.getName().compareTo(s1.getName());
}
}
Согласно вашему вопросу, он также будет работать, когда значения указанного поля будут изменены. Вы должны помнить только для вызова метода sort
с этим компаратором.
Ответ 3
В java у вас есть два основных способа сравнения объектов.
Первым для самого класса является реализация интерфейса Comparable, который будет означать только одну реализацию.
Второй способ состоит в том, чтобы классы реализовывали Comparator интерфейс. Таким образом, вы можете иметь несколько компараторов для одного и того же класса.
Это означает, что вы могли бы определить, например, 3 сопоставителя diffenrent в вашем классе StudentVo: один, который сравнивается только с именем, другой, который сравнивает возрастные и последние, которые оба свойства.
В вашем приложении вы используете реализацию, которая вам подходит, на основе того, что вы хотите сравнить. В одном месте вы будете сравнивать студентов по возрасту Collections.sort(myStudents, новый CompareStudentOnAge()). В другом месте вы используете другую реализацию.
Вы можете найти некоторые пояснения в этом сообщении в блоге: http://javarevisited.blogspot.fr/2011/06/comparator-and-comparable-in-java.html
Ответ 4
Мне недавно пришлось решить эту проблему. Не уверен, что это точно такой же сценарий, как ваш, но мне пришлось написать сортировку в памяти для нулевого или большего количества столбцов сетки, ручную работу над условиями OOM и т.д., Потому что моя проблема была очень ограниченной по охвату.
Я написал компаратор для каждого столбца и компаратор, который взял список компараторов. Когда я определил, какие столбцы нужно сортировать и в каком порядке, я добавил экземпляр соответствующего компаратора в список компараторов. Затем используйте цепной компаратор для выполнения фактического сортировки.
public class MyObject
{
private String name;
private int age;
private Date registered;
}
Итак, что-то вроде этого для каждого компаратора:
public class NameComparator
implements Comparator<MyObject>
{
public int compare(MyObject o1, MyObject o2)
{
return o1.getName().compareTo(o2.getName);
}
}
Это для цепного компаратора:
public class ChainedComparator
implements Comparator<MyObject>
{
public int compare(MyObject o1, MyObject o2) {
for(Comparator<MyObject> comparator : comparators) {
int result = comparator.compare(o1,o2);
if(result != 0) {
return result;
}
}
return 0;
}
}
private List<Comparator<MyObject>> comparators = new ArrayList<>();
}
Слева к вашему воображению анализируется сортировка и построение цепного компаратора. Я на самом деле сделал это немного сложнее, потому что я также включил направление, которое я реализовал, заменив порядок параметров в вызове субкомпозитора в прикованном компараторе по мере необходимости.
Ответ 5
Новый подход для этого в java-8
см. Сравнение компаратора #
и Компаратор # thenComparing. Все, что вам нужно, это предоставить ссылку на выражение lamda или метод метода Stream#sorted()
или List#sort()
.
Например, сортировка по одному полю:
List<StudentVO> students = Arrays.asList(
new StudentVO(20,"Bob"),
new StudentVO(19, "Jane")
);
// sort by age
students.stream()
.sorted(Comparator.comparing(StudentVO::getAge))
.forEach(System.out::println);
// [StudentVO{age=19, name='Jane'},StudentVO{age=20, name='Bob'}]
// sort by name
students.stream()
.sorted(Comparator.comparing(StudentVO::getName))
.forEach(System.out::println);
// [StudentVO{age=20, name='Bob'}, StudentVO{age=19, name='Jane'}]
Сортировка по нескольким полям:
List<StudentVO> students = Arrays.asList(
new StudentVO(20,"Bob"),
new StudentVO(19, "Jane"),
new StudentVO(21,"Bob")
);
// by age and then by name
students.stream()
.sorted(Comparator
.comparing(StudentVO::getAge)
.thenComparing(StudentVO::getName)
).forEach(System.out::println);
// [StudentVO{age=19, name='Jane'}, StudentVO{age=20, name='Bob'}, StudentVO{age=21, name='Bob'}]
// by name an then by age
students.stream()
.sorted(Comparator
.comparing(StudentVO::getName)
.thenComparing(StudentVO::getAge)
).forEach(System.out::println);
// [StudentVO{age=20, name='Bob'}, StudentVO{age=21, name='Bob'}, StudentVO{age=19, name='Jane'}]