考虑以下示例,其中我们根据人员的姓氏对其进行排序:
public class ComparatorsExample {
public static class Person {
private String lastName;
public Person(String lastName) {
this.lastName = lastName;
}
public String getLastName() {
return lastName;
}
@Override
public String toString() {
return "Person: " + lastName;
}
}
public static void main(String[] args) {
Person p1 = new Person("Jackson");
Person p2 = new Person("Stackoverflowed");
Person p3 = new Person(null);
List<Person> persons = Arrays.asList(p3, p2, p1);
persons.sort(Comparator.comparing(Person::getLastName));
}
}
现在,假设getLastName
返回一个可选的:
public Optional<String> getLastName() {
return Optional.ofNullable(lastName);
}
显然persons.sort(Comparator.comparing(Person::getLastName));
不会编译,因为Optional
(类型getLastName
返回)不可比。但是,它拥有的价值是。
谷歌的第一个搜索为我们指出了这个答案。根据此答案,我们可以通过以下方式对人员进行排序:
List<Person> persons = Arrays.asList(p3, p2, p1);
OptionalComparator<String> absentLastString = absentLastComparator(); //type unsafe
persons.sort((r1, r2) -> absentLastString.compare(r1.getLastName(), r2.getLastName()));
我的问题是,是否有可能像Comparator.comparing一样使用函数(键提取器)进行这种排序?
我的意思是(不关心第一个或最后一个缺少的值):
persons.sort(OptionalComparator.comparing(Person::getLastName));
如果查看Comparator.comparing,我们将看到以下代码:
public static <T, U extends Comparable<? super U>> Comparator<T> comparing(
Function<? super T, ? extends U> keyExtractor) {
Objects.requireNonNull(keyExtractor);
return (Comparator<T> & Serializable) (c1, c2) -> {
return keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2));
};
}
我尝试了多种方法使它返回OptionalComparator
a Comparator
,而不是简单的,但是我尝试过的所有有意义的事情都无法编译。甚至有可能实现这样的目标?我猜想类型安全性无法实现,因为甚至Oracle都comparing
抛出了类型安全性警告。
我正在使用Java 8。
您可以使用Comparator#comparing(Function,Comparator)
:
接受一个从类型中提取排序键的函数
T
,并返回一个Comparator<T>
使用指定的键与该排序键进行比较的函数Comparator
。
这是一个基于您问题代码的示例:
persons.sort(comparing(Person::getLastName, comparing(Optional::get)));
基本上,这是使用嵌套键提取程序来最终比较String
代表姓氏的对象。请注意,NoSuchElementException
如果其中一个Optional
为空,则将引发a 。您可以创建一个更复杂的方法Comparator
来处理empty Optional
s 1:
// sort empty Optionals last
Comparator<Person> comp =
comparing(
Person::getLastName,
comparing(opt -> opt.orElse(null), nullsLast(naturalOrder())));
persons.sort(comp);
如果需要大量执行此操作,请考虑以类似于Comparator#nullsFirst(Comparator)
和Comparator#nullsLast(Comparator)
1的方式创建实用程序方法:
// empty first, then sort by natural order of the value
public static <T extends Comparable<? super T>> Comparator<Optional<T>> emptyFirst() {
return emptyFirst(Comparator.naturalOrder());
}
// empty first, then sort by the value as described by the given
// Comparator, where passing 'null' means all non-empty Optionals are equal
public static <T> Comparator<Optional<T>> emptyFirst(Comparator<? super T> comparator) {
return Comparator.comparing(opt -> opt.orElse(null), Comparator.nullsFirst(comparator));
}
// empty last, then sort by natural order of the value
public static <T extends Comparable<? super T>> Comparator<Optional<T>> emptyLast() {
return emptyLast(Comparator.naturalOrder());
}
// empty last, then sort by the value as described by the given
// Comparator, where passing 'null' means all non-empty Optionals are equal
public static <T> Comparator<Optional<T>> emptyLast(Comparator<? super T> comparator) {
return Comparator.comparing(opt -> opt.orElse(null), Comparator.nullsLast(comparator));
}
然后可以这样使用:
persons.sort(comparing(Person::getLastName, emptyLast()));
1.根据@Holger提供的建议简化了示例代码。如果有好奇的话,请看一下编辑历史,以查看代码之前的样子。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句