Geo*_* Z. 8 java collections lambda optional comparator
考虑以下示例,其中我们根据姓氏对人员进行排序:
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));
}
}
Run Code Online (Sandbox Code Playgroud)
现在,让我们假设getLastName返回一个可选的:
public Optional<String> getLastName() {
return Optional.ofNullable(lastName);
}
Run Code Online (Sandbox Code Playgroud)
显然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()));
Run Code Online (Sandbox Code Playgroud)
我的问题是,是否可以像 Comparator.comparing 一样使用函数(键提取器)进行这种排序?
我的意思是(首先或最后不关心缺失值):
persons.sort(OptionalComparator.comparing(Person::getLastName));
Run Code Online (Sandbox Code Playgroud)
如果我们查看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));
};
}
Run Code Online (Sandbox Code Playgroud)
我尝试了多种方法使其返回 anOptionalComparator而不是 simple Comparator,但是我尝试过的并且对我有意义的所有内容都无法编译。甚至有可能实现这样的目标吗?我猜无法实现类型安全,因为即使是 Oracle 也会comparing抛出类型安全警告。
我在 Java 8 上。
您可以使用Comparator#comparing(Function,Comparator):
接受从类型中提取排序键的函数
T,并返回Comparator<T>使用指定的排序键进行比较的Comparator。
这是基于您问题中的代码的示例:
persons.sort(comparing(Person::getLastName, comparing(Optional::get)));
Run Code Online (Sandbox Code Playgroud)
基本上这是使用嵌套的密钥提取器来最终比较String代表姓氏的对象。请注意,NoSuchElementException如果其中一个Optional为空,这将导致抛出a 。您可以创建一个更复杂Comparator的处理空Optionals 1:
// sort empty Optionals last
Comparator<Person> comp =
comparing(
Person::getLastName,
comparing(opt -> opt.orElse(null), nullsLast(naturalOrder())));
persons.sort(comp);
Run Code Online (Sandbox Code Playgroud)
如果您需要大量执行此操作,请考虑以类似于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));
}
Run Code Online (Sandbox Code Playgroud)
然后可以像这样使用:
persons.sort(comparing(Person::getLastName, emptyLast()));
Run Code Online (Sandbox Code Playgroud)
1. 根据@Holger提供的建议简化示例代码。如果好奇,请查看编辑历史记录以查看代码之前的样子。
| 归档时间: |
|
| 查看次数: |
680 次 |
| 最近记录: |