Самый простой, статичный c способ сделать это может состоять в том, чтобы просто сохранить имя поля -> Карта компаратора, например:
private static Map<String, Comparator<Person>> comparatorMap = Map.of(
"age", Comparator.comparing(Person::getAge),
"firstName", Comparator.comparing(Person::getFirstName),
"lastName", Comparator.comparing(Person::getLastName),
"country", Comparator.comparing(Person::getCountry)
);
Который, учитывая список полей, такой как
List<String> sortFields = Arrays.asList("age", "firstName", "lastName");
может использоваться для создания составного компаратора:
Optional<Comparator<Person>> chainedComparator =
sortFields.stream().map(comparatorMap::get).reduce(Comparator::thenComparing);
personList.stream().sorted(chainedComparator.get());
Вы также можете заметить, что я использовал Comparator
собственный thenComparing
для составления компараторов (вместо того, чтобы реализовывать его самостоятельно).
Вот пример реализации , использующий отражение для динамического выбора полей для сортировки по
Перед его использованием, обратите внимание: * Предполагается, что fields относятся к Comparable
типам (если вы передадите имя поля, тип которого несопоставим, возникнет исключение приведения класса) * Я создаю компаратор каждый раз, вы можете сохранить их для поля имя, если это необходимо
private static Comparator<Person> personFieldComparator(String field) {
return (person1, person2) -> readPersonField(person1, field)
.compareTo(readPersonField(person2, field));
}
private static Comparable<Object> readPersonField(Person person, String field) {
try {
Field f = Person.class.getDeclaredField(field);
f.setAccessible(true);
return (Comparable<Object>) f.get(person);
} catch (IllegalAccessException | IllegalArgumentException
| NoSuchFieldException e) {
throw new RuntimeException(e); //proper handling needed
}
}
И с этим вы можете изменить первоначальную реализацию на что-то вроде:
Optional<Comparator<Person>> chainedComparator = sortFields.stream()
.map(Main::personFieldComparator) //Main -> Your class name
.reduce(Comparator::thenComparing);
personList.stream().sorted(chainedComparator.orElseThrow())...;
Вы можете расширить это с помощью обобщений, чтобы сделать это не Person
-specifi c