带有密钥提取器的 Optional<T> 的比较器,例如 java.util.Comparator.comparing
Comparator for Optional<T> with key extractor, like java.util.Comparator.comparing
考虑以下示例,我们根据姓氏对人员进行排序:
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("Whosebuged");
Person p3 = new Person(null);
List<Person> persons = Arrays.asList(p3, p2, p1);
persons.sort(Comparator.comparing(Person::getLastName));
}
}
现在,我们假设 getLastName
return 是一个可选的:
public Optional<String> getLastName() {
return Optional.ofNullable(lastName);
}
显然 persons.sort(Comparator.comparing(Person::getLastName));
不会编译,因为 Optional
(类型 getLastName
returns)不是可比较的。然而,它所持有的价值是。
第一个 google 搜索将我们指向 。根据这个答案,我们可以通过以下方式对人员进行排序:
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));
};
}
我尝试了多种方法使它 return 成为 OptionalComparator
而不是简单的 Comparator
,但我尝试过的所有对我有意义的东西都无法编译。 甚至有可能实现这样的目标吗? 我猜类型安全无法实现,因为即使是 Oracle 的 comparing
也会抛出类型安全警告。
我在 Java 8.
您可以使用 Comparator#comparing(Function,Comparator)
:
Accepts a function that extracts a sort key from a type T
, and returns a Comparator<T>
that compares by that sort key using the specified Comparator
.
这是一个基于您问题中的代码的示例:
persons.sort(comparing(Person::getLastName, comparing(Optional::get)));
基本上这是使用嵌套键提取器来最终比较表示姓氏的 String
对象。请注意,如果 Optional
为空,这将导致抛出 NoSuchElementException
。您可以创建一个更复杂的 Comparator
来处理空 Optional
s1:
// 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:[=28= 的方式创建实用程序方法]
// 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 提供的建议简化了示例代码。如果好奇的话,看看编辑历史,看看以前的代码是什么样子。
帮助很大,根据他的回答,我得到了我想要的。然而,正如他提到的
persons.sort(comparing(Person::getLastName, comparing(Optional::get));
如果 Optional
的值不存在, 将抛出异常。这样一来,我们就错过了大部分 OptionalComparator
点感。但幸运的是它可以转换为:
persons.sort(comparing(Person::getLastName, absentFirstComparator()));
将处理不存在值的情况。
另外,可以创建这两个方法:
public static <T, U extends Optional> Comparator<T> absentFirst(Function<? super T, ? extends U> keyExtractor) {
Objects.requireNonNull(keyExtractor);
return (Comparator<T>) (c1, c2) -> absentFirstComparator().compare(keyExtractor.apply(c1),
keyExtractor.apply(c2));
}
public static <T, U extends Optional> Comparator<T> absentLast(Function<? super T, ? extends U> keyExtractor) {
Objects.requireNonNull(keyExtractor);
return (Comparator<T>) (c1, c2) -> absentLastComparator().compare(keyExtractor.apply(c1),
keyExtractor.apply(c2));
}
最后我得到了我想要的:
persons.sort(absentLast(Person::getLastName));
考虑以下示例,我们根据姓氏对人员进行排序:
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("Whosebuged");
Person p3 = new Person(null);
List<Person> persons = Arrays.asList(p3, p2, p1);
persons.sort(Comparator.comparing(Person::getLastName));
}
}
现在,我们假设 getLastName
return 是一个可选的:
public Optional<String> getLastName() {
return Optional.ofNullable(lastName);
}
显然 persons.sort(Comparator.comparing(Person::getLastName));
不会编译,因为 Optional
(类型 getLastName
returns)不是可比较的。然而,它所持有的价值是。
第一个 google 搜索将我们指向
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));
};
}
我尝试了多种方法使它 return 成为 OptionalComparator
而不是简单的 Comparator
,但我尝试过的所有对我有意义的东西都无法编译。 甚至有可能实现这样的目标吗? 我猜类型安全无法实现,因为即使是 Oracle 的 comparing
也会抛出类型安全警告。
我在 Java 8.
您可以使用 Comparator#comparing(Function,Comparator)
:
Accepts a function that extracts a sort key from a type
T
, and returns aComparator<T>
that compares by that sort key using the specifiedComparator
.
这是一个基于您问题中的代码的示例:
persons.sort(comparing(Person::getLastName, comparing(Optional::get)));
基本上这是使用嵌套键提取器来最终比较表示姓氏的 String
对象。请注意,如果 Optional
为空,这将导致抛出 NoSuchElementException
。您可以创建一个更复杂的 Comparator
来处理空 Optional
s1:
// 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:[=28= 的方式创建实用程序方法]
// 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 提供的建议简化了示例代码。如果好奇的话,看看编辑历史,看看以前的代码是什么样子。
persons.sort(comparing(Person::getLastName, comparing(Optional::get));
如果 Optional
的值不存在, 将抛出异常。这样一来,我们就错过了大部分 OptionalComparator
点感。但幸运的是它可以转换为:
persons.sort(comparing(Person::getLastName, absentFirstComparator()));
将处理不存在值的情况。
另外,可以创建这两个方法:
public static <T, U extends Optional> Comparator<T> absentFirst(Function<? super T, ? extends U> keyExtractor) {
Objects.requireNonNull(keyExtractor);
return (Comparator<T>) (c1, c2) -> absentFirstComparator().compare(keyExtractor.apply(c1),
keyExtractor.apply(c2));
}
public static <T, U extends Optional> Comparator<T> absentLast(Function<? super T, ? extends U> keyExtractor) {
Objects.requireNonNull(keyExtractor);
return (Comparator<T>) (c1, c2) -> absentLastComparator().compare(keyExtractor.apply(c1),
keyExtractor.apply(c2));
}
最后我得到了我想要的:
persons.sort(absentLast(Person::getLastName));